Skip to content

Adopt generated component manifest and audit sensitive settings - #454

Merged
paul-phan merged 3 commits into
mainfrom
feat/agent-component-manifest
Aug 5, 2026
Merged

Adopt generated component manifest and audit sensitive settings#454
paul-phan merged 3 commits into
mainfrom
feat/agent-component-manifest

Conversation

@paul-phan

Copy link
Copy Markdown
Member

Closes #452. Part of the agent-ready composition RFC.

Makes Pilot the first repository-native, agent-readable Weaverse theme.

What this adds

  • .weaverse/component-manifest.json — a committed, deterministic description of all 82 registered components: settings, non-sensitive defaults, child rules, limits, presets, loader presence, and availability metadata.
  • DESIGN.md — brand tokens, accessibility requirements, component rules, prohibited patterns, worked examples.
  • .agents/weaverse.md — manifest regeneration, sensitivity rules, safe composition guidance.
  • CI — Pilot's first PR workflow.
npm run weaverse:manifest         # regenerate
npm run weaverse:manifest:check   # fail on drift (CI)
npm run weaverse:audit            # registrations + sensitivity (CI)

The generator loads the real registry through Vite's SSR module runner, so it sees exactly what the storefront registers. It never executes loaders, evaluates availability callbacks, or reads merchant content. Function-based rules are recorded as {"dynamic": true}.

Defects found and fixed

Duplicate registrations. 84 entries, 82 unique — Blogs and BlogPost were each registered twice. The generator now refuses to serialize duplicates, so this cannot silently return.

Non-deterministic manifest. Two consecutive runs differed:

- "defaultValue": 1785043618655
+ "defaultValue": 1785043619668

countdown--timer computed its schema default from new Date() at module load, making drift checking structurally impossible. The fallback moved into the component.

That also exposed a latent bug: an unset endTime produced undefined - Date.now()NaN, and every NaN <= 0 comparison is false, so the timer rendered garbage instead of zeros. Guarded with Number.isFinite.

Unclassified credential. aliReviewsApiKey held a third-party bearer token as a plain text input. Now sensitive: true, so the SDK redacts its value everywhere.

Dependency requirement

Requires @weaverse/hydrogen@5.19.0. The previous release pinned @weaverse/schema@0.12.0, which predates both sensitive and the @weaverse/schema/manifest subpath:

error TS2353: 'sensitive' does not exist in type 'BasicInput'.

An npm overrides workaround was rejected — Pilot is the reference theme, so the stale pin would propagate downstream. Fixed properly upstream in v5.19.0.

Two notes for reviewers

The heuristic is not the security boundary. sensitive: true is what redacts a value; name matching only catches what a human forgot to classify. The initial pattern matched bare auth, flagging authorName/authorTitle/authorImage/showAuthor. Allowlisting four legitimate content fields would train reviewers to ignore the check, so the pattern was tightened instead. One justified exception remains: popularSearchKeywords.

Biome must not touch the manifest. Reformatting it would corrupt the canonical bytes and invalidate the hash. Using files.includes turned out to replace the inherited list rather than merge it — warnings jumped 3 → 100. Resolved with a scoped overrides entry that leaves the shared config intact.

Verification

Check Result
npm run typecheck pass
npm run biome 3 warnings, 0 errors — identical to baseline main
npm run weaverse:manifest:check up to date, 82 components
npm run weaverse:audit pass, 489 settings
Regenerate twice byte-identical, same hash
Duplicate registration generator rejects
Unmarked credential audit fails
Marked sensitive passes, value absent from manifest
Secret in nested preset array audit fails with exact path
Tampered manifest drift check fails
Countdown unset/past/future/NaN correct in all four

Every guard was verified by making it fail first, then pass.

CI gates were checked against unmodified main before being enabled, so this workflow is green on arrival rather than importing pre-existing debt.

Manifest hash: sha256:d075f0d922f2cedcdb395cba93ee4d5a99d967015f7b9730c3d591ec81056ca5

Make Pilot the first repository-native, agent-readable Weaverse theme by
committing a deterministic component manifest and enforcing it in CI.

Adds `.weaverse/component-manifest.json`, generated from the real registry
through Vite's SSR module runner so it reflects exactly what the storefront
registers. Generation never executes loaders, evaluates availability
callbacks, or reads merchant content.

Fixes three defects found during the audit:

- `Blogs` and `BlogPost` were each registered twice (84 entries, 82 unique).
- `countdown--timer` computed its schema default from `new Date()` at module
  load, making the manifest differ from itself on every run. Moving the
  fallback into the component also fixes a latent `NaN` cascade that rendered
  garbage when `endTime` was unset.
- `aliReviewsApiKey` held a third-party bearer token as an unclassified text
  input; it is now `sensitive: true`.

Requires `@weaverse/hydrogen@5.19.0`. The previous release pinned
`@weaverse/schema@0.12.0`, which predates both `sensitive` and the
`@weaverse/schema/manifest` subpath.

Pilot had no PR workflow, so this adds one. Typecheck and lint were verified
green against unmodified `main` first, so the gate does not import existing
debt.

Refs #452, Weaverse/weaverse#493
Comment thread .github/workflows/ci.yml Fixed
@paul-phan

Copy link
Copy Markdown
Member Author

@codex review

CodeQL flagged the new workflow for relying on the repository default
GITHUB_TOKEN permissions. The job only reads the checkout, so scope it
explicitly to contents: read.
@paul-phan

Copy link
Copy Markdown
Member Author

@codex 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: eb5cb15c25

ℹ️ 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".

// manifest non-deterministic and its drift check unusable. An unconfigured
// timer instead falls back to one day from mount, held stable for the
// component's lifetime.
const [fallbackEndTime] = useState(() => Date.now() + ONE_DAY);

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 Initialize the fallback deadline consistently during hydration

When the countdown preset supplies no endTime, this initializer runs independently during server rendering and browser hydration. Because calculateRemainingTime calls Date.now() again and floors every unit, crossing a millisecond boundary between those calls can make one render show 1d 0:0:0 while the other shows 0d 23:59:59; React then reports a hydration mismatch and regenerates this subtree. Use a hydration-stable initial display or establish the clock after mounting.

Useful? React with 👍 / 👎.

Comment on lines +115 to +118
const surfaces = {
presets: component.presets,
examples: component.examples,
};

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 Scan setting defaults for leaked secret values

The recursive secret scan only visits presets and examples, so a secret-shaped defaultValue on a non-sensitive setting with an innocuous name is never checked here or by the name heuristic. Such a schema can pass this audit while committing the credential directly into the manifest; include setting defaults in the scanned surfaces as well. .agents/weaverse.mdL60-L74

Useful? React with 👍 / 👎.

Resolves package.json against main's dependency refresh: main dropped
@shopify/hydrogen-react and moved to @weaverse/hydrogen ^5.19.2, which
supersedes the ^5.19.0 bump this branch carried. Lockfile taken from main
unchanged, since the resulting dependency set is now identical.

Regenerates the manifest for main's theme version and the spacer childTypes
added since this branch forked.

Review fixes:

- Audit now scans `settings` for secret-shaped values. `defaultValue` lives
  there, so a hardcoded credential under a benign name (`apiEndpoint`) passed
  clean before. The name heuristic misses it and the value-shape check was
  only looking at presets and examples.
- Drops the dead REVIEWED_SAFE allowlist. Its only entry was a theme setting,
  which never enters the component manifest, so the branch never reached it.
- Drift error no longer claims schemas changed. A version bump alone triggers
  it, which made the message wrong on every release PR.
- Release process regenerates the manifest after the version bump, so release
  PRs stop failing the new gate.
- Removes the biome overrides block. Main's files.includes already excludes
  .weaverse, so biome.json is now identical to main.
@paul-phan
paul-phan merged commit cf27105 into main Aug 5, 2026
5 checks passed
@paul-phan
paul-phan deleted the feat/agent-component-manifest branch August 5, 2026 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Agent composition] Adopt the generated component manifest and audit sensitive settings

2 participants