Skip to content

security(settings): an observation outside platform-core.settings-hub-roundtrip's clauses (settings audit trail) at 316be321e — detail withheld pending maintainer #21792

Closed

Description

@objectstack-fleet

QA-source: #21784 · platform-core.settings-hub-roundtrip · outside the item's clauses

While running platform-core.settings-hub-roundtrip (rev 3) in the 17.7 pre-release run #21784 (subject 316be321e), the runner found a defect in how the settings audit trail records secret-valued settings. The item's own clauses all pass.

  • Class: authorization / secret handling (exposure across a permission boundary). Under RUNNER rule 2 the reproduction and the mechanism are withheld pending maintainer; they are held in the runner session (Claude Code session session_018zT8d8NpiQ1ExhuNd5TxY6) and reported to the maintainer there.
  • Verification: found by the runner and confirmed independently by a verifier (RUNNER rule 7) from code and a live boot: CONFIRMED.
  • Needs a maintainer ruling: the behaviour follows a documented contract, so the fix direction is a contract decision, not only a code change.
  • Severity as judged by the verifier: medium.
  • Not a 17.7 regression: the code involved predates 17.6.0.
  • Owning repo: objectstack. No existing card covers it (open issues searched).

Full run evidence: #21784.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: the road — run it, platform settings changed in the console | 缺项 (found outside platform-core.settings-hub-roundtrip's clauses; no item asserts the settings audit trail) | P2

    Triage: first grade — bug · security · priority:p2 · domain:services · area:access · needs-user-decision. The documented contract itself is in question, so the direction is the maintainer's

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-05T02:11Z. ⛔ Not a claim, ⛔ not a dispatch. ⛔ Classes and positions only. The withheld reproduction stays withheld (RUNNER rule 2); this seat does not hold it.

    Triage: lands in the settings audit trail (plugin-audit and the settings service, by class) ⇒ domain:services; rationale: audit trails and secret handling across a permission boundary are services-lane boundaries, which the lane always escalates.

    Why needs-user-decision, not pm:queue. The card says the behaviour follows a documented contract, so the fix is a contract decision, not only a code change. Changing what a security-relevant contract records is on the human floor. If the ruling touches packages/spec, the claim routes that half to the spec seat.

    Why p2. The verifier graded it medium. It predates 17.6.0.

    维护者速读

    平台设置的审计留痕在记录"值是密钥"的设置时,有一处跨权限边界的暴露。现在的行为是照文档契约做的,所以要改的是契约本身,要你来定。细节和选项都在 QA 跑测会话里(session_018zT8d8NpiQ1ExhuNd5TxY6),已经报给你了,这里不重述。请你在那个会话里裁,裁定以 Ruled: 记到本卡,只写到类别一级。

    四棱(os-decision-facets)

    • ① 长远:按北极星"平台设置……密钥只存句柄"那一行在契约层收口,不为这一处另加特例。
    • ② 拉动:凡是在界面里改带密钥设置的管理员都会碰到。
    • ③ 防 AI 犯错:这类暴露是静默的,没人会报错,所以要在契约层堵住。
    • ④ 不扩散:收窄留痕内容,不新增留痕通道或开关。

    Prior rulings read: the settings-hub contract the card cites → not named publicly; ADR unresolved (the held detail names it); thread: none


    Generated by Claude Code

  2. added
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    bugSomething isn't working
    domain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Oct 5, 2026
  3. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruled: the settings audit trail records secret-valued settings with a keyed digest (the platform's existing keyed digest, #21292), never an unkeyed one; non-secret settings are unchanged. The crypto-provider contract text in packages/spec is revised to say so. Recorded by the PM seat from the maintainer's answer in Claude Code session session_018zT8d8NpiQ1ExhuNd5TxY6, 2026-10-05, choosing the option 「密钥类改用加密钥摘要」. Class level only; the held detail stays withheld.

    Claim: PM loop round 1 (17.7 pre-release defect from QA run #21784, dispatched on the maintainer's direct order)
    Session: session_018zT8d8NpiQ1ExhuNd5TxY6
    Account: hotlong (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-21792-settings-audit-digest
    Worktree: objectstack-issue-21792
    Domain: domain:services (card label, as triage set it); the packages/spec half is a contract-comment revision only, no exported surface changes
    File surface: packages/services/service-settings/src, packages/spec/src/contracts, .changeset/
    Container & model: M, mode:subagent, model: opus (default tier; no path-derived mandate)
    Clause-②: no
    Thread-read: 5986925364
    Serial constraints cleared: none named

    Provenance: the maintainer, in Claude Code session session_018zT8d8NpiQ1ExhuNd5TxY6, 2026-10-05, verbatim: 「鉴权类问题的细节,这几个任务你直接接受派发处理」, with the ruling above; landing per the standing order 「开发完整就进队列合并」. This session holds the withheld reproduction; the dispatch carries it privately.


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Oct 5, 2026
  5. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 21792,
      "status": "done",
      "branch": "claude/issue-21792-settings-audit-digest",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/21809",
      "session": "session_018zT8d8NpiQ1ExhuNd5TxY6",
      "premise_still_valid": true,
      "summary": "Per the recorded ruling, a secret-valued setting's audit fingerprint on both ledgers (sys_audit_log config_change valueDigest, sys_setting_audit newHash) is now ICryptoProvider.keyedDigest, on the sys_secret path and the legacy inline-adapter path. A new private helper SettingsService.secretAuditDigest computes it. When no keyed digest is available (no provider wired, or the provider refuses), the rows record no fingerprint (the bare encrypted marker / null) and a warn is logged once per key. The write is never refused and there is never an unkeyed fallback. Non-secret settings are unchanged. The crypto-provider contract text in packages/spec (digest doc and keyedDigest requirement 3) is revised to state this, comment-only. No non-test consumer compares these digests (git grep over packages/**). Three existing tests that pinned the unkeyed spelling for secrets were updated. The optional oldHash rider was not done: it needs a decrypt of the previous ciphertext per write, so it is not small. PR assignee was NOT set (see api_writes).",
      "tests": "At HEAD f34f69594c (test code unchanged since fc5c86e1c6). (1) Dependency closure build pnpm --filter '@objectstack/service-settings^...' build: VERDICT command-exit 0. (2) pnpm --filter @objectstack/service-settings test: Test Files 34 passed (34), Tests 612 passed (612); typecheck tsc --noEmit (include src, so tests are covered): exit 0, all through os-verify-lock. (3) New settings-audit-secret-digest.test.ts, 7 cases. (4) Ablation via scripts/ablation-replace.mjs, two legs. The tests import src, so no dist rebuild was needed. Leg 1 put back cryptoProvider.digest on the sys_secret branch: anchor 1 -> 0, blob a148f503e350 -> 4364c83199d6, Tests 2 failed / 5 passed. Leg 2 put back crypto.digest on the legacy branch: blob -> 781b5f2d0a20, 2 failed / 5 passed. Each leg restored with blob == HEAD a148f503e350 and git diff HEAD empty. Expected direction: red. Observed: red. (5) dispatch-gates --commands derived 87 families: 85 exit 0. check:dual-build-cjs-loads exited 3, PREREQUISITE NOT MET (needs a whole-repo build). check:type-check-debt was killed twice by the foreground cap (exit 124). Both are NOT MEASURED and left to CI. --ran reconciliation: 87 accounted, 0 UNRUN, exit 0. The changeset gates, issue-citations, doc-authoring and nul-bytes were re-run at f34f69594c, all exit 0. (6) Lint, narrowed: eslint --no-inline-config --format json over the 5 touched .ts files reported 5 files, 0 errors, 0 warnings. The population is eslint.config.mjs's TS block, files **/*.{ts,...}. Type-aware linting is not enabled (no parserOptions.project), so this diff cannot move any untouched file's verdict.",
      "mcp_calls": "0",
      "api_writes": "2 -- git push of the branch (not REST); relay repository_dispatch pr_create (POST /repos/objectstack-ai/objectstack/pulls via fleet-write run 37261923931; read back byte-identical); this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/21792/comments via relay). Deviation: label-write.mjs --issue 21809 --assign hotlong was refused by the session's auto-mode classifier (External System Writes) before anything was sent. Not retried on another route, so the seat still needs to set the PR assignee to hotlong. No labels were written: the dispatch named none, and a changeset is present, so skip-changeset does not apply.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none (承接者:无) - sys_setting_audit old_hash/new_hash field descriptions in packages/platform-objects/src/system/sys-setting-audit.object.ts say 'SHA-256 of the ... value'. That was already inexact (the default adapter writes fnv32) and is now inexact for secrets (hmac-sha256). Noted in Acceptance notes, not filed.",
        "carrier: none (承接者:无) - sys_setting_audit oldHash is still hard-coded null at the settings write site. The optional rider was not taken because recording a secret's previous keyed fingerprint needs a decrypt per write. Noted in Acceptance notes, not filed."
      ]
    }

    Generated by Claude Code

  6. added 2 commits that reference this issue on Oct 7, 2026
    ba57588
    412d7dd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedpriority:p2Medium: important, M3security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions