Skip to content

Commit 18d5ba2

Browse files
committed
chore(changeset): narrow the api-secret changeset to the three CLI commands
The Clause-② line matches the PR body again (os validate / os build / os lint only). The publish-gate sentences go, replaced by one saying the gate is deliberately not covered yet. The Why paragraph and the ADR-0087 reason name 17.5.0, the release whose published changelog carries the engine's registration refusal, instead of "the same release". Claude-Session: https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5dde7e6 commit 18d5ba2

1 file changed

Lines changed: 12 additions & 18 deletions

File tree

‎.changeset/20553-validate-api-flow-secret.md‎

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,30 @@
22
'@objectstack/lint': minor
33
---
44

5-
`os validate` refuses an `api` flow with no per-flow secret, the flow the automation engine already refuses to register (#20553).
5+
`os validate`, `os build` and `os lint` refuse an `api` flow with no per-flow secret, the flow the automation engine already refuses to register (#20553).
66

7-
Clause-②: yes (narrowing — `os validate` / `os build` / `os lint` and the runtime metadata publish gate newly refuse a secretless `api`-bound flow; the new exported rule id `FLOW_API_TRIGGER_SECRET_MISSING` widens `@objectstack/lint`)
7+
Clause-②: yes (narrowing — `os validate` / `os build` / `os lint` newly refuse a secretless `api`-bound flow; the new exported rule id `FLOW_API_TRIGGER_SECRET_MISSING` widens `@objectstack/lint`)
88

9-
<!-- adr-0087: not-required (no-migration-prescription) Nothing authorable changes spelling or type: `packages/spec` is untouched, and the start node `config` stays the open record it was. What changes is that two authoring doors, `os validate` / `os build` / `os lint` and the runtime metadata publish gate, now refuse one authored shape: an `api`-bound flow whose start node carries no usable `config.secret`. `objectstack migrate meta` could not rewrite that shape even in principle, because the missing value is a shared secret only the author and the sending system can supply. A stored flow of that shape is already refused at registration by `@objectstack/service-automation` in the same release, whose own changeset carries this same disposition for that load path; the publish gate judges only the item being written, so no stored row is re-judged here. -->
9+
<!-- adr-0087: not-required (no-migration-prescription) Nothing authorable changes spelling or type: `packages/spec` is untouched, and the start node `config` stays the open record it was. What changes is that three authoring commands, `os validate` / `os build` / `os lint`, now refuse one authored shape: an `api`-bound flow whose start node carries no usable `config.secret`. `objectstack migrate meta` could not rewrite that shape even in principle, because the missing value is a shared secret only the author and the sending system can supply. A stored flow of that shape has been refused at registration by `@objectstack/service-automation` since 17.5.0, whose published changelog entry records that load path's disposition; nothing here judges a stored row. -->
1010

11-
**BREAKING** — an accept-set narrowing at two authoring doors, shipped as
11+
**BREAKING** — an accept-set narrowing on three authoring commands, shipped as
1212
`minor` under the launch-window convention (`check-changeset-no-major` refuses
1313
`major` until GA; breaking-ness is carried by this banner and the ADR-0087
1414
disposition above, not by the level). A stack that declares an `api`-bound flow
1515
whose start node carries no usable `config.secret` used to pass `os validate`,
16-
`os build` and `os lint`; they now exit non-zero and name the flow. The runtime
17-
metadata publish gate used to pass a `state: 'active'` write of such a flow; it
18-
now refuses it before the flow is stored. **One-line fix:** set a non-blank
19-
`config.secret` on the flow's start node — or, for a flow that is only ever
20-
started explicitly, declare `type: 'autolaunched'` with no `triggerType: 'api'`.
16+
`os build` and `os lint`; they now exit non-zero and name the flow.
17+
**One-line fix:** set a non-blank `config.secret` on the flow's start node — or,
18+
for a flow that is only ever started explicitly, declare `type: 'autolaunched'`
19+
with no `triggerType: 'api'`.
2120

22-
`validate-flow-trigger-readiness` gains one rule id, `flow-api-trigger-secret-missing`, at `error`. It names a flow whose binding resolves to the inbound `api` trigger when that flow's start node carries no usable `config.secret`. A usable secret is a string that is non-empty after trimming. The rule fires for a missing, blank or non-string secret, and for an `api` flow with no start node.
21+
`@objectstack/lint` gains one rule id, `flow-api-trigger-secret-missing`, at `error`, emitted by a new exported rule, `validateFlowApiTriggerSecret`, in the `validate-flow-trigger-readiness` family. It names a flow whose binding resolves to the inbound `api` trigger when that flow's start node carries no usable `config.secret`. A usable secret is a string that is non-empty after trimming. The rule fires for a missing, blank or non-string secret, and for an `api` flow with no start node.
2322

24-
**Why.** ADR-0041's `trigger-api` acceptance criteria require a per-flow secret with HMAC verification. In the same release, the automation engine refuses such a flow in `registerFlow`, whatever its `status`: the `/automation` write doors answer `400`, and a boot skips the flow with a warning. `ApiTrigger.start()` also refuses to arm it. `os validate` builds neither, so it answered `✓ Validation passed` for a flow no runtime would register. It now exits non-zero and names the flow.
23+
**Why.** ADR-0041's `trigger-api` acceptance criteria require a per-flow secret with HMAC verification. Since 17.5.0 the automation engine refuses such a flow in `registerFlow`, whatever its `status`: the `/automation` write doors answer `400`, and a boot skips the flow with a warning. `ApiTrigger.start()` also refuses to arm it. `os validate` builds neither, so it answered `✓ Validation passed` for a flow no runtime would register. It now exits non-zero and names the flow.
2524

2625
**Which flows count as `api`-bound.** The rule uses the engine's own binding, `deriveTriggerBinding`. An array-form record `triggerType` goes to the record-change trigger first. Otherwise the flow gets the kind `resolveFlowTriggerKind` answers, which is a flow declaring `type: 'api'` or a start-node `triggerType: 'api'`. The engine gives the record-change, time-relative and schedule triggers precedence over `api`. So a `type: 'api'` flow whose start node also carries a `record-*` token, a `timeRelative` descriptor or a `config.schedule` binds that other trigger. The engine never asks that flow for a secret, and the rule stays silent on it.
2726

28-
**Where the refusal surfaces.** The rule is `CLI_AND_RUNTIME`, so it gates in two places:
29-
30-
- `os validate`, `os build` and `os lint`.
31-
- The runtime metadata publish gate. A `state: 'active'` write of a secretless `api` flow now carries this `error`, so the gate refuses it before the flow is stored. Before this change the gate passed that write.
32-
33-
The gate judges only the item being written, so existing stored flows are not re-judged.
27+
**Where the refusal surfaces.** `os validate`, `os build` and `os lint`. The runtime metadata publish gate is deliberately not covered yet (#20611): it judges a `/meta` save before the stored secret the flow read path withholds is restored, so for now a secretless flow saved there is still stored, and the engine then refuses it at registration.
3428

3529
**Fix.** Set a non-blank `config.secret` on the flow's start node, and sign each post with it in the `x-objectstack-signature` header. A flow that is only ever started explicitly and never receives inbound posts is `type: 'autolaunched'`, with no `triggerType: 'api'` on its start node, and it needs no secret.
3630

37-
`FLOW_API_TRIGGER_SECRET_MISSING` is exported from `@objectstack/lint`.
31+
`validateFlowApiTriggerSecret` and `FLOW_API_TRIGGER_SECRET_MISSING` are exported from `@objectstack/lint`.

0 commit comments

Comments
 (0)