Skip to content

Align managed-namespace tenant signer with generated VerbAgent ENS#387

Merged
GsCommand merged 1 commit into
mainfrom
codex/fix-managed-namespace-signer-identity-generation
Jun 17, 2026
Merged

Align managed-namespace tenant signer with generated VerbAgent ENS#387
GsCommand merged 1 commit into
mainfrom
codex/fix-managed-namespace-signer-identity-generation

Conversation

@GsCommand

Copy link
Copy Markdown
Contributor

Motivation

  • Prevent signer identity mismatches in managed-namespace packages where the claim-level tenant_signer_ens could point at the tenant root (e.g. acme.eth) while generated agent records used managed agent ENS (e.g. acme.attestagent.eth).
  • Ensure the claim pipeline, recovery key, and UI consistently reference the managed agent ENS as the signing identity in managed-namespace mode while preserving BYO/root behavior.

Description

  • Updated claim intake handler in api/claim/commandlayer-namespace.js to validate managed-namespace submissions and require that the submitted tenantSignerEns matches the first generated managed agent ENS, and to reject agent TXT records whose cl.receipt.signer does not match that agent's ENS.
  • Persisted a primaryTenantSignerEns value in the request JSON for clarity (kept inside request_json and not adding DB columns), and continued to store the corrected tenant_signer_ens and tenant_signer_txt_records into claim_requests.
  • Updated the UI/package generation in public/claim.html to derive tenant_signer_ens from the first generated agent when activation_mode === 'managed_namespace', add primary_tenant_signer_ens to generated manifests, surface a clear label Signer ENS: ..., and add helper text: Managed namespace mode signs receipts from the generated VerbAgent ENS, not the tenant root ENS.
  • Added server-side utility to extract per-agent TXT records and threaded agent records through safeAgent so agent-level cl.receipt.signer can be validated; kept per-agent records signing behavior so each agent still uses its own ENS as cl.receipt.signer.
  • Added tests in tests/claim-activation-pipeline.test.js covering: managed namespace UI/package signer derivation, claim submission storing generated agent ENS and TXT signer, multi-capability primary signer selection while preserving per-agent signers, BYO/root signer preservation, and rejection cases for managed signer mismatches.

Testing

  • Ran npm test and all tests passed (157 tests currently, no failures).
  • Ran npm run check:links and link checks passed (all local links resolved).
  • New/updated automated tests added in tests/claim-activation-pipeline.test.js include assertions for UI/package behavior, claim persistence of tenant_signer_ens and primaryTenantSignerEns, BYO behavior, and rejection cases; these tests passed under the test run above.

Codex Task

@vercel

vercel Bot commented Jun 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
commandlayer-commandlayer-org Ready Ready Preview, Comment Jun 17, 2026 12:12am
commandlayer-org Ready Ready Preview, Comment Jun 17, 2026 12:12am
commandlayer-org111 Ready Ready Preview, Comment Jun 17, 2026 12:12am

Request Review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 433ebced93

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread public/claim.html
const names = agentNames();
return (names[0] || state.ens || '').toLowerCase();
}
return (state.ens || '').toLowerCase();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Align BYO ENS records with the submitted signer

When activation mode is own, this now submits tenantSignerEns as the root state.ens, but buildENSRecords() still tells users to publish TXT records on each generated sub-agent with cl.receipt.signer=${name}. The status verifier resolves the stored claim.tenant_signer_ens and compares the four records there, so a BYO namespace user who follows Step 5 publishes records for e.g. approve.acme.eth while the claim verifies acme.eth, leaving activation stuck at records_unavailable/records_mismatch.

Useful? React with 👍 / 👎.


function recordsFromAgent(agent) {
const card = agent && agent.cardJson && typeof agent.cardJson === 'object' ? agent.cardJson : {};
const records = agent && agent.records && typeof agent.records === 'object' ? agent.records : card.records;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check card JSON signer before accepting managed agents

When a managed API client includes an agent.records object that omits cl.receipt.signer, this line stops looking at cardJson.records; the mismatched signer in cardJson is then persisted into claim_agents and can be pinned by api/admin/pin-agent-cards.js. For example, records: {} plus cardJson.records['cl.receipt.signer'] = 'acme.eth' returns 202 instead of managed_agent_signer_mismatch, so the new validation can be bypassed for the card records that downstream publication uses.

Useful? React with 👍 / 👎.

Comment thread public/claim.html
Comment on lines +676 to +677
const names = agentNames();
return (names[0] || state.ens || '').toLowerCase();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Derive managed signer from effective canonical verbs

When a managed namespace is built by selecting/removing canonical parents directly, getEffectiveClVerbs() drives the submitted agents but this path still uses agentNames(), which reads getVerbs() from the pack/cherry state. If no pack is selected, or the canonical parent list no longer matches the pack, tenantSignerEns falls back to the tenant root or a different first agent while the payload's first agent comes from selectedCanonicalParents, and the new server-side managed_signer_mismatch check rejects the activation request.

Useful? React with 👍 / 👎.

Comment on lines +88 to +89
if (tenantSignerEns !== primaryManagedSignerEns) {
return invalid(res, 'managed_signer_mismatch', 'Managed namespace tenantSignerEns must match the first generated managed agent ENS.');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate the managed signer is a generated agent

This only checks that tenantSignerEns equals the first submitted agent ENS, so an API client can still submit a managed-namespace claim with both values set to the tenant root, e.g. tenantSignerEns: 'acme.eth' and agents[0].ens: 'acme.eth'. That passes the new guard, stores managed_ens_parent_namespace as eth, and reintroduces the root-signer managed claim that this change is meant to reject unless the code also verifies the ENS is the expected ${tenant}.${canonicalParent} managed agent.

Useful? React with 👍 / 👎.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant