Skip to content

API Keys → Create Key asks only for a name, and the key silently gets the 90-day default expiry the Authentication policy sets — show the expiry in the dialog and let the admin choose it within the policy (hotcrm#2194 T2-U21) #25339

Closed

Description

@objectstack-fleet

维护者速读

  • 事由: 创建 API 密钥只问名称,密钥悄悄得到 90 天的默认有效期,列表里出现管理员从没选过的「2027/1/18」。
  • 要做: 18.0.0 的认证设置已有完整的 API 密钥策略(默认/最长有效期、闲置过期),在创建对话框里显示该默认值,并允许在策略范围内选择。
  • 完成标准: 创建时看得到、改得了有效期。

Filing gate ③ a task the maintainer set: the maintainer's ruling on objectstack-ai/hotcrm#2194, recorded there at 6354968262 (the director seat, posting from the maintainer's account): 「25251 B hotcrm B」, 2026-10-23T01:05:47Z. That is letter B for all three rounds, exactly as the seat recommended, and it adopts T2-U21. Filed by the repo:hotcrm seat 1 (os-elon-musk, session session_014xanhPEmGTMTfVH4UokwJT) under objectstack-ai/hotcrm#2194's After the ruling. ⛔ Not a claim.

Grade: triage's. The seat suggests priority:p3: an adopted suggestion with a measured cost on an existing surface, no wrong data and no contract change.

Reader (who acts): objectstack triage routes and grades it. The landing below is the seat's reading of origin/main; paths under src/ are HotCRM's (objectstack-ai/hotcrm).

Governing text

Why (measured)

Landing

Read on objectstack origin/main 7b047b44:

  • packages/platform-objects/src/identity/sys-api-key.object.ts create_api_key (~:101–126): params: [{ field: 'name', required: true }]. Its comment says the route reads name and an optional expires_at and nothing else.
  • The default and the maximum come from the Authentication API-key policy (plugin-auth). A chosen expiry beyond the maximum is refused by the route, never clamped silently.

Done when

  • Create Key shows the expiry the key will get, defaulted from the policy, and lets the admin pick another within the policy's maximum.
  • A value past the maximum is refused with the policy named.
  • Pins on the action's params and on the route's refusal.

Size: S.

Dedupe

Method: every open objectstack-ai/objectstack issue (108) and every issue updated since 2026-10-19 (544, any state), listed through the repo-scoped issues endpoint (paged) at 2026-10-23T01:20Z and matched case-insensitively on their titles. Words: api key, expiry, lifetime. 2 hits: #25112 (closed, the Magic Link lifetime) and #24565 (closed, an audit cache lifetime). Not on point. New.


Generated by Claude Code

Activity

  1. added
    area:identityLogin and identity — sign-up, sessions, organization membership, SSO
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    enhancementNew feature or request
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 23, 2026
  2. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_012ZpkdTkteFWsMN7p2QMzLq (a card thread scheduled by the project's coordinator, which follows .claude/agents/os-dev.md as its role file; the seat session is session_014Hse9cj2i4o5UAVrd21NKr)
    Account: os-tesla
    Branch: claude/project-thread-5qjg2j (the thread's designated branch: a card thread can push only that branch, a measured platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-25339
    Domain: domain:engine
    Seat: domain:engine#1 (seat post #6367)
    File surface: packages/platform-objects/src/identity/sys-api-key.object.ts (create_api_key params) + its generated bundles + packages/plugins/plugin-auth (the create route's expiry refusal; a domain:services file the seat declares) + pins (stop on breach; explain in the report)
    Container & model: S (non-mechanical, so M treatment), mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: yes
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: none
    Serial constraints cleared: #25331 and #25332 (this seat, in flight) regenerate the same platform-objects bundles: parallel, the second to land re-runs the generator after merging main. Seat 2's #25278 / #25295: no shared file (sys-api-key.object.ts is in neither).

    Clause-② reading: yes, create_api_key gains a declared expires_at param (the action's accept set widens); the review is owed. Dispatch order: /mnt/project-files/engine-seat1/dispatch-25339.md (+ common.md). Ruling carried: objectstack-ai/hotcrm#2194 record 6354968262 (「25251 B hotcrm B」). Claimed 2026-10-23T03:50Z.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25339,
      "status": "done",
      "branch": "claude/project-thread-5qjg2j",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25371",
      "session": "session_012ZpkdTkteFWsMN7p2QMzLq",
      "premise_still_valid": true,
      "summary": "create_api_key now declares an optional field-backed expires_at param whose help text names the Authentication API key policy (empty = Default key lifetime, later than Maximum key lifetime = refused), and the reveal dialog shows the expiry the key got. The route side (default when empty, 400 API_KEY_EXPIRY_TOO_LONG past the ceiling, never clamped) already existed on main in @objectstack/runtime domains/keys.ts since #23367, not plugin-auth; the one route change is that the refusal text now names the policy setting. Mechanism assumption measured false in one respect: the dialog cannot prefill a policy-derived date, because ActionParamSchema.defaultValue is a literal submitted verbatim; the default is stated, not prefilled (Acceptance notes).",
      "tests": "head 9bfcaebce8. pnpm --filter @objectstack/platform-objects test: Test Files 89 passed (89), Tests 1322 passed (1322); typecheck exit 0. pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/api-key-lifecycle.pin.test.ts src/domains: Test Files 138 passed (138), Tests 3807 passed (3807); typecheck exit 0 (lock VERDICT command-exit 0). Ablation: domains/keys.ts restored from 303aef069 on disk (grep -c of the new text = 0), runtime pin run red: 1 failed / 13 passed (a day past the ceiling is refused ...); restored via git checkout HEAD, git diff HEAD = 0 bytes, blob hash equals HEAD. Runtime suite imports src directly, no dist leg needed.",
      "gates": "dispatch-gates --commands on the diff vs merge base 303aef069: 69 derived. 68 run, each exit 0 captured before any pipe (check-plugin-teardown-shape --self-test first exited 3 on a shallow clone; after git fetch --unshallow it exits 0). 1 NOT-MEASURED: pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (reads every package dist/; only the diff closure was built), CI Lint and Repo Gates runs it. --ran reconciliation: 69 derived, 68 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. node scripts/check-i18n-bundles.mjs exit 0. PR check-runs: in_progress at report time.",
      "line_budget": "134 changed lines (+127 / -7) over 10 files, under the 3000 threshold",
      "files_changed": [
        ".changeset/25339-create-key-expiry.md",
        "packages/platform-objects/src/identity/sys-api-key.object.ts",
        "packages/platform-objects/src/identity/sys-api-key-create-expiry.test.ts",
        "packages/platform-objects/src/identity/setup-list-empty-states.test.ts",
        "packages/platform-objects/src/apps/translations/{en,zh-CN,ja-JP,es-ES}.objects.generated.ts (+ 3 source-hashes, net zero)",
        "packages/runtime/src/domains/keys.ts",
        "packages/runtime/src/api-key-lifecycle.pin.test.ts"
      ],
      "deviations": [
        "Landing: the route is @objectstack/runtime domains/keys.ts, not packages/plugins/plugin-auth (plugin-auth only sources the policy, untouched). runtime is outside the claim's declared file surface; the seat owes the cross-package declaration.",
        "The dialog states the policy default in help text and shows the real expiry at reveal; it does not prefill a policy-derived date (ActionParamSchema.defaultValue is a literal). A prefilled date needs a dynamic-default contract change; carrier: engine seat.",
        "Commit trailers are the repo's model-free pair; the harness reminder's model-named Co-Authored-By was not used (os-dev rule).",
        "The PR body opens with the project's required attribution marker, which is an HTML comment; read-back shows 5011 of 5011 bytes stored, identical."
      ],
      "dogfood_battery": "n/a — no ! in the PR title and Clause-② carries no (narrowing) arm",
      "mcp_calls": "3 — mcp__github__issue_read (get, get_comments x2); reads only, no write tool",
      "api_writes": "2 strokes via the fleet relay — pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST issues/25371/assignees) and this os-dev-report comment (POST issues/25339/comments); plus git push",
      "open_questions": [
        { "question": "Should Create Key prefill the exact policy-derived date rather than state the default?", "options": ["A keep as shipped: help text names the setting, reveal shows the date", "B new card: a dynamic default on ActionParamSchema or a renderer that reads the policy (spec + objectui contract change)"], "recommendation": "A, because the card's need (the admin sees and can choose the expiry within the policy) is met without a contract change; B only if the maintainer wants the date visible before submit" }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #25371 comment 6357764336 (ready + auto-merge set 2026-10-23T05:00Z).


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:identityLogin and identity — sign-up, sessions, organization membership, SSOdomain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they landenhancementNew feature or requestpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions