Skip to content

Commit 4afd3c8

Browse files
claude[bot]claude
andauthored
docs(qa): correct the federation auth-floor texts against head's capability gate (#11582)
`integration-system.external-schema-introspection` was authored 2026-08-20 against `79ebb37`, when the federation route spelling served a caller holding no capability while its admin twin refused. #9901 (reads + writes) and #10255 (validate) closed that asymmetry, so the item's auth-floor texts do not merely go stale — they invert: a runner following them today observes the correct 403 on the federation spelling, and the clause names the old behaviour "a DELIBERATE, pinned divergence (#9593), not a hole to file", pre-empting the escape hatch. Rewrite the four texts to the twin-agreement posture (step 8, the auth-floor clause, its verify, and the `external-datasource-routes.ts` source entry whose `:26-28`/`:215-260` anchors were stale), plus persona 1 and step 7, which attributed the capability to the admin spelling alone. Companion `cli.datasource-introspect-codegen`: all three `os datasource` subcommands address federation READ routes, so a merely-authenticated token now 403s every clause. Name `manage_platform_settings` in both personas and in the token fixture, and record the all-403 run as a negative so a runner re-mints instead of filing the landed gate as a CLI regression. Both items take a `revision` bump and a `history` entry. Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx Co-authored-by: Claude <noreply@anthropic.com>
1 parent 90932b0 commit 4afd3c8

2 files changed

Lines changed: 20 additions & 12 deletions

File tree

docs/qa/platform-checklist/areas/cli.json

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,15 +1150,15 @@
11501150
"title": "os datasource list-tables/introspect/validate: the federation door answers, the generated draft is cwd-jailed and compiles, and schema drift maps to ✗ diffs with exit 1",
11511151
"since": "v16",
11521152
"status": "active",
1153-
"revision": 1,
1153+
"revision": 2,
11541154
"priority": "P2",
11551155
"surface": "cli",
1156-
"personas": ["operator (local shell)", "integration author (adopting a remote table)"],
1156+
"personas": ["operator (local shell) whose token HOLDS manage_platform_settings — all three commands address federation READ routes, which require it since #9901/#10255", "integration author (adopting a remote table), same capability"],
11571157
"fixtures": {
11581158
"app": "showcase",
11591159
"requires": [
11601160
"a booted showcase (`pnpm dev -- --fresh -p <port>`) — it ships the external datasource fixture: examples/app-showcase/src/system/datasources/showcase-external.datasource.ts (name 'showcase_external', sqlite file .objectstack/data/showcase_external.db) seeded by external-fixture.ts",
1161-
"an admin session token minted via POST /api/v1/auth/sign-in/email (the external-datasource routes sit behind the auth guard — external-datasource-routes-auth-guard.test.ts); pass it as --token / OS_TOKEN, with --url / OS_CLOUD_URL pointing at the boot port",
1161+
"an admin session token minted via POST /api/v1/auth/sign-in/email for a user HOLDING manage_platform_settings — authentication alone is NOT enough since #9901/#10255: every route these three commands address is a federation READ (list-tables → GET /external/tables, introspect → POST /external/tables/:remote/draft, validate → POST /external/validate), and each opens with refuseFederationRequest, which answers 401 UNAUTHENTICATED with no identity and then 403 PERMISSION_DENIED naming FEDERATION_READ_CAPABILITY = manage_platform_settings (external-datasource-routes.ts:157, :287-324; pinned in external-datasource-routes-auth-guard.test.ts). Pass it as --token / OS_TOKEN, with --url / OS_CLOUD_URL pointing at the boot port",
11621162
"a scratch objects/ dir in the invocation cwd for the --out draft, and a scratch config to wire the draft into for the compile clause"
11631163
],
11641164
"knownGaps": [
@@ -1217,7 +1217,8 @@
12171217
"an --out escape that lands a server-authored file outside the project tree is the security FAIL the jail exists for — the refusal must be proven, not assumed from the code",
12181218
"validate exiting 0 while an error-severity diff printed breaks every CI wrapper watching for schema drift",
12191219
"a draft that does not compile through os build makes the adoption workflow a dead end — the whole point of codegen",
1220-
"route-spelling trap: the CLI addresses /external/tables (federation, packages/rest); probing the admin /remote-tables spelling and reading its 404 as 'the CLI's route is gone' conflates two mounts — the API-door coverage of the admin twin belongs to the integration-system area, not here"
1220+
"route-spelling trap: the CLI addresses /external/tables (federation, packages/rest); probing the admin /remote-tables spelling and reading its 404 as 'the CLI's route is gone' conflates two mounts — the API-door coverage of the admin twin belongs to the integration-system area, not here",
1221+
"wrong-persona shape, NOT a finding: all three commands failing alike with the server's 403 PERMISSION_DENIED naming manage_platform_settings means the token authenticated but is unentitled — re-mint it for a caller holding that capability and re-run before filing anything. Filing it as a CLI or route regression would be a report against the #9901/#10255 gate working as ruled"
12211222
],
12221223
"traps": ["dispatcher-vs-hono-route", "seed-data-thin", "wrong-persona"],
12231224
"source": [
@@ -1228,7 +1229,8 @@
12281229
"sibling item cli.flag-command-error-ux (owned only the topic's --help until now)"
12291230
],
12301231
"history": [
1231-
{ "revision": 1, "date": "2026-08-20", "change": "new — scoped scan-functionality sweep (扫描功能): the datasource topic's three subcommands had only a --help variant, no functional coverage. Re-verified against source during authoring: the hunter brief asked whether an --out escape refusal exists — it DOES (introspect.ts:65-74, absolute + traversal both refused before any write), so the jail is asserted positively with both escape probes rather than worded observe-and-flag. The /external/tables-vs-/remote-tables mount split is recorded as a runner trap with the admin twin explicitly routed to the integration-system area", "ref": "claude/new-session-0pv25p" }
1232+
{ "revision": 1, "date": "2026-08-20", "change": "new — scoped scan-functionality sweep (扫描功能): the datasource topic's three subcommands had only a --help variant, no functional coverage. Re-verified against source during authoring: the hunter brief asked whether an --out escape refusal exists — it DOES (introspect.ts:65-74, absolute + traversal both refused before any write), so the jail is asserted positively with both escape probes rather than worded observe-and-flag. The /external/tables-vs-/remote-tables mount split is recorded as a runner trap with the admin twin explicitly routed to the integration-system area", "ref": "claude/new-session-0pv25p" },
1233+
{ "revision": 2, "date": "2026-08-24", "change": "spell the CAPABILITY persona out. Read in the same pass as #11138 and confirmed rather than assumed: this item was authored 2026-08-20 against the pre-#9901 federation door, so its fixture asked only for \"an admin session token\" behind \"the auth guard\" — the #9686 AUTHENTICATION floor. At head all three commands address federation READ routes (list-tables GET /external/tables, introspect POST /external/tables/:remote/draft, validate POST /external/validate), each gated on FEDERATION_READ_CAPABILITY = manage_platform_settings by #9901/#10255, so a merely-authenticated token 403s every clause in the item. The capability is now named in both personas and in the token fixture, and the resulting all-403 run is recorded as a negative (the wrong-persona trap this item already declares) so a runner re-mints instead of filing the landed gate as a CLI regression", "ref": "#11138" }
12321234
]
12331235
},
12341236
{

docs/qa/platform-checklist/areas/integration-system.json

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,11 +1153,11 @@
11531153
"title": "External-datasource schema introspection happy path: remote-tables lists live tables with columnCount (?schema= honoured since #7955), object-draft renders a reviewable *.object.ts, both route spellings answer as one operation behind the platform auth floor",
11541154
"since": "v16",
11551155
"status": "active",
1156-
"revision": 1,
1156+
"revision": 2,
11571157
"priority": "P1",
11581158
"surface": "api",
11591159
"personas": [
1160-
"admin — authenticated AND holding manage_platform_settings (the admin spelling's capability gate, #9391/#9593)",
1160+
"admin — authenticated AND holding manage_platform_settings (BOTH spellings' capability gate since #9901/#10255: admin #9391/#9593, federation FEDERATION_READ_CAPABILITY)",
11611161
"a second authenticated persona holding NO capability, plus an anonymous probe (for the auth-floor clause)"
11621162
],
11631163
"fixtures": {
@@ -1178,8 +1178,8 @@
11781178
"GET /api/v1/datasources/showcase_external/external/tables (the twin spelling) — compare the set against step 2",
11791179
"POST /api/v1/datasources/showcase_external/object-draft with body { \"table\": \"customers\" }, and the twin POST /api/v1/datasources/showcase_external/external/tables/customers/draft with body {} — record both drafts",
11801180
"write draft.source to a scratch file and typecheck it (it imports only a type from @objectstack/spec/data) — the compilable-*.object.ts check",
1181-
"run the pinned suites: packages/rest/src/remote-tables-twin.equivalence.test.ts (the #7955 request-shape cases + the #9686/#9593 admission cases)",
1182-
"replay remote-tables + object-draft with NO credential (expect 401 on BOTH spellings), then as the no-capability session (expect 403 on the ADMIN spelling only — the federation spelling serves, the pinned #9593 divergence)"
1181+
"run the pinned suites: packages/rest/src/remote-tables-twin.equivalence.test.ts (the #7955 request-shape cases + the #9686/#9593/#9901 admission cases, incl. the two that pin the twins refusing an UNENTITLED caller identically)",
1182+
"replay remote-tables + object-draft with NO credential (expect 401 UNAUTHENTICATED on BOTH spellings), then as the no-capability session (expect 403 PERMISSION_DENIED naming manage_platform_settings on BOTH spellings — #9901/#10255 CLOSED the #9593 divergence, so a 200 to that session on the federation spelling is now a FAIL, not the documented behaviour)"
11831183
],
11841184
"acceptance": [
11851185
{
@@ -1207,9 +1207,9 @@
12071207
"evidence": "the test run output + the paired live reads"
12081208
},
12091209
{
1210-
"clause": "the auth floor holds, with its documented asymmetry: an anonymous caller is refused 401 UNAUTHENTICATED on BOTH spellings (admin: requireDatasourceAdmin/#9391; federation: refuseAnonymous/#9686 — fail-closed, before any service lookup so an anonymous probe cannot learn what is wired); an authenticated caller WITHOUT manage_platform_settings is refused 403 PERMISSION_DENIED naming the capability on the ADMIN spelling only, while the federation spelling serves — a DELIBERATE, pinned divergence (#9593), not a hole to file",
1210+
"clause": "the auth floor holds and BOTH spellings answer it IDENTICALLY — the #9593 asymmetry this item recorded through rev 1 is CLOSED, so a federation 200 to an unentitled caller is a FAIL, not the documented behaviour: an anonymous caller is refused 401 UNAUTHENTICATED on BOTH spellings (admin: requireDatasourceAdmin/#9391; federation: refuseFederationRequest's shouldDenyAnonymous arm/#9686 — fail-closed, before any service lookup so an anonymous probe cannot learn what is wired), and an authenticated caller WITHOUT manage_platform_settings is refused 403 PERMISSION_DENIED naming the capability on BOTH spellings, keyed on that capability rather than on holding merely some grant. Federation READS (tables, draft) took FEDERATION_READ_CAPABILITY = manage_platform_settings in #9901 — maintainer ruling 2026-08-20, verbatim: 「其他接受你的建议。」— and validate joined them in #10255 (verbatim: 「同意你的意见。」); the family's WRITES (import, refresh-catalog — outside this item's probes) sit on FEDERATION_WRITE_CAPABILITY = manage_metadata above the same 401 floor",
12111211
"oracle": "api",
1212-
"verify": "the four probes of step 8 against admin-routes.ts:361-420 (401 then capability 403) and external-datasource-routes.ts refuseAnonymous (401 only, capability check deliberately absent per its #9593 note); the divergence case is pinned in the twin test's 'WHO may ask' describe",
1212+
"verify": "the four probes of step 8 against admin-routes.ts:361-420 (401 floor then manage_platform_settings 403) and external-datasource-routes.ts:287-324 refuseFederationRequest (the same two decisions out of ONE resolveExecutionContext call — anonymous first, then FEDERATION_READ_CAPABILITY); the agreement is pinned in the twin test's 'listRemoteTables twins agree on WHO may ask (#9686, #9593, #9901)' describe, whose two unentitled cases compare the two spellings' status AND code to each other rather than to a literal",
12131213
"evidence": "the 401/403/200 responses"
12141214
}
12151215
],
@@ -1229,7 +1229,7 @@
12291229
},
12301230
"source": [
12311231
"packages/services/service-datasource/src/admin-routes.ts:517-560 (remote-tables + the #7955 coercion comment), :611-623 (object-draft), :361-420 + :261 (requireDatasourceAdmin — 401 floor then manage_platform_settings 403, #9391/#9593)",
1232-
"packages/rest/src/external-datasource-routes.ts:26-28, :215-260 (the twin family GET /external/tables + POST .../draft; anonymous-deny floor #9686; capability gate deliberately absent — the file's own #9593 note)",
1232+
"packages/rest/src/external-datasource-routes.ts:409-448 (the twin family GET /external/tables + POST .../draft), :287-324 (refuseFederationRequest — the #9686 anonymous-deny floor, then the #9901/#10255 capability gate, both decided from one resolveExecutionContext call with anonymous first), :157 (FEDERATION_READ_CAPABILITY = manage_platform_settings, what the two twin routes require) + :172 (FEDERATION_WRITE_CAPABILITY = manage_metadata, the family's write half)",
12331233
"packages/services/service-datasource/src/external-datasource-service.ts:137 (listRemoteTables schema filter + allowedSchemas), :183 (generateObjectDraft), :445-481 (renderObjectSource; :465 the generated header)",
12341234
"packages/drivers/driver-sql/src/sql-driver.ts:9661 (introspectSchema; SQLite branch reads sqlite_master → bare unqualified table names)",
12351235
"examples/app-showcase/src/system/datasources/ (showcase-external.datasource.ts + external-fixture.ts)",
@@ -1241,6 +1241,12 @@
12411241
"date": "2026-08-20",
12421242
"change": "new item from the scoped scan-functionality (扫描功能) coverage sweep: the introspection HAPPY PATH was uncovered — datasource-admin-lifecycle proves only the unwired-503 arm (and since serve.ts:2966 wires federation unconditionally, that arm is unit-pin territory on a stock boot). Covers remote-tables + object-draft on the shipped SQLite fixture, the #7955 ?schema= fix (asserted as fixed, live-limited on SQLite — see knownGaps), twin-spelling equivalence, and the #9391/#9686/#9593 auth floor incl. its pinned divergence",
12431243
"ref": "claude/new-session-0pv25p"
1244+
},
1245+
{
1246+
"revision": 2,
1247+
"date": "2026-08-24",
1248+
"change": "correct the auth-floor texts: the #9593 federation/admin asymmetry this item was authored against (2026-08-20, at 79ebb37) had already been CLOSED by #9901 (reads + writes, 9a1ed7a09) and #10255 (validate, 6ce58a735), so four texts asserted a posture head no longer has — and they INVERT rather than go quiet: a runner would have scored the correct federation 403 as a deviation, with \"a DELIBERATE, pinned divergence (#9593), not a hole to file\" pre-empting the escape hatch. Rewritten to the twin-agreement posture: step 8, this clause, its verify (which read \"capability check deliberately absent\"), and the external-datasource-routes.ts source entry whose :26-28/:215-260 anchors were stale; also persona 1 and step 7, which attributed the capability to the admin spelling alone. Re-verified at 0320a52d, not inherited: all five federation routes open with refuseFederationRequest (reads manage_platform_settings, writes manage_metadata) above the #9686 401 floor, and remote-tables-twin.equivalence.test.ts now compares the two spellings on an unentitled caller instead of pinning a divergence",
1249+
"ref": "#11138"
12441250
}
12451251
]
12461252
},

0 commit comments

Comments
 (0)