You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
service-automation: a flow http node that sets signingSecret sends its request unsigned on the inline arm (and on the durable arm's no-outbox fallback), while the published contract promises X-Objectstack-Signature #20628
The flow's http node sets signingSecret, method: POST and a control header.
Non-durable (the default): the request arrives with the control header and with no X-Objectstack-Signature, and no signature-like header at all. The run reports success: true.
durable: true with no messaging outbox wired (the documented degrade to the inline arm): the same result, unsigned and success: true. The only log line is the existing inline-fallback warning, which does not say the signature was dropped.
Reader who acts: the triage seat (#6015) grades and routes it. It then goes to the domain:services seat. The fix lands in packages/services/service-automation/src/builtin/http-nodes.ts, the request/response arm below the durable branch.
Filed by the domain:services seat (#6021, session_01XY5uCwTjZj7884yYtyur4H). It comes from the at-tier contract review of PR #20615 (record 5886643746, escalation R2), measured in that PR's patch round 1. ⛔ Filed bare: grading and routing are triage's. ⛔ Not a claim.
What is declared, and what runs
Declared, published:HttpConfigSchema.signingSecret in packages/spec/src/automation/io-node-config.zod.ts reads .describe('HMAC-SHA256 secret → X-Objectstack-Signature'). The http descriptor's configSchema in builtin/http-nodes.ts says the same. Neither says "durable only".
Runs: only the durable arm hands signingSecret to the messaging outbox (enqueueHttp), which signs. The inline arm builds its fetch from cfg.headers and never reads signingSecret.
So an author, human or AI, who sets the key on the default arm gets a request the receiving endpoint cannot authenticate, and no signal that the key did nothing. The same happens to a durable node on a host with no outbox.
Direction (a suggestion, not a ruling)
Per the enforce-or-remove principle, a declared key that runs nowhere is an implementation gap: enforce it or retire it. ⛔ Do not narrow the description at the consumer.
Enforce: the inline arm signs with the outbox's scheme, the same header and the same HMAC input, so one key means one thing on both arms. The durable no-outbox fallback then signs too.
Retiring the key or making it durable-only would be a contract change, which is the spec lane's work and moves Clause-②. That route is for the maintainer to choose, not the implementer.
A pin: for each arm, with a signingSecret set, the received request carries a signature that verifies, or the node refuses.
Filing gate: ① a product defect with a named landing site.
reach:measured at the executor seam every flow run takes, with a real request to a local receiver. The measurement was taken by the [security] closeout: two stored-credential positions outside #20552's projection still reach a served read unredacted (a flow http node's signingSecret; the /meta list read's raw fallback) #20590 dev in patch round 1 of PR fix(service-automation,metadata-protocol,runtime): withhold the remaining stored flow-credential positions at every depth, and answer a /meta list fault as itself (#20590) #20615, and is recorded in itsos-dev-reporton [security] closeout: two stored-credential positions outside #20552's projection still reach a served read unredacted (a flow http node's signingSecret; the /meta list read's raw fallback) #20590.httpnode setssigningSecret,method: POSTand a control header.X-Objectstack-Signature, and no signature-like header at all. The run reportssuccess: true.durable: truewith no messaging outbox wired (the documented degrade to the inline arm): the same result, unsigned andsuccess: true. The only log line is the existing inline-fallback warning, which does not say the signature was dropped.Reader who acts: the triage seat (#6015) grades and routes it. It then goes to the
domain:servicesseat. The fix lands inpackages/services/service-automation/src/builtin/http-nodes.ts, the request/response arm below the durable branch.Filed by the
domain:servicesseat (#6021,session_01XY5uCwTjZj7884yYtyur4H). It comes from the at-tier contract review of PR #20615 (record5886643746, escalation R2), measured in that PR's patch round 1. ⛔ Filed bare: grading and routing are triage's. ⛔ Not a claim.What is declared, and what runs
HttpConfigSchema.signingSecretinpackages/spec/src/automation/io-node-config.zod.tsreads.describe('HMAC-SHA256 secret → X-Objectstack-Signature'). Thehttpdescriptor'sconfigSchemainbuiltin/http-nodes.tssays the same. Neither says "durable only".signingSecretto the messaging outbox (enqueueHttp), which signs. The inline arm builds itsfetchfromcfg.headersand never readssigningSecret.Direction (a suggestion, not a ruling)
success: true". This is the answer the webhook precedents took: [security] a stored webhook signing secret that resolves to null is treated as "authored unsigned" — the subscription arms and delivers UNSIGNED #8542 refused to deliver unsigned when a stored secret did not resolve, and [security] the same stored-but-unresolvable collapse #8542 fixes for the signing secret is still open onresolveWebhookHeaders— the delivery goes out MISSING its authored headers #8558 did the same for its headers.Clause-②. That route is for the maintainer to choose, not the implementer.signingSecretset, the received request carries a signature that verifies, or the node refuses.Related, not the same
resolveWebhookHeaders— the delivery goes out MISSING its authored headers #8558 (closed):plugin-webhooks' own signing path, a different executor.Dedupe
MCP
search_issues(a read),objectstack-ai/objectstack, open and closed, run 2026-09-29 by this seat:plugin-webhooks).redeliverbutton that sends UNSIGNED #8069, closed, webhook redeliver).resolveWebhookHeaders— the delivery goes out MISSING its authored headers #8558, [security] a stored webhook signing secret that resolves to null is treated as "authored unsigned" — the subscription arms and delivers UNSIGNED #8542).ExternalDataSourceSchema.authentication(clientSecret/apiKey) andMessageQueueConfigSchema.sasl.password— census toward #7990's parked boundary-guard reopen trigger #8075, [security] a stored webhook signing secret that resolves to null is treated as "authored unsigned" — the subscription arms and delivers UNSIGNED #8542).httpnode's inline arm.Dedupe words:
http node signingSecret inline unsigned·durable fallback inline drops signature·X-Objectstack-Signature inline request