Skip to content

AppPlugin registers artifact security metadata in memory from the RAW bundle, bypassing the artifact door's ADR-0087 conversion — a second unconverted reader of the same bytes #12844

Description

@os-zhuang

Observation recorded while fixing #12772 (dev seat of PM session session_01SVYmuhHW6qZmNBqciaS7BN; fix PR: #12843). Filed as a finding — no reachable defect measured today — for the triage round to grade.

What was measured

The framework artifact boot reads the same artifact bytes through TWO independent readers:

  1. MetadataPlugin._parseAndRegisterArtifact (packages/metadata/src/plugin.ts) — re-reads the artifact file named by artifactSource, strict-parses it, and (since feat(metadata): versioned ADR-0087 forward conversion at the artifact-ingestion door #12843) runs the versioned ADR-0087 forward conversion first. Registered items are canonical.
  2. AppPlugin (packages/runtime/src/app-plugin.ts, the ADR-0057 block) — receives the bundle from loadArtifactBundle (packages/runtime/src/load-artifact-bundle.ts, no validation, no conversion) and registers positions / permissions / capabilities / sharingRules / policies items into the metadata service via registerInMemory, RAW.

So after an artifact boot of a pre-17.2 artifact, the converted copy (keys stripped) and the raw copy (keys present) of the same permission sets both enter the metadata registry, and which one a reader sees depends on registration order and read path.

Why no defect is reachable today

Why it is still worth a card

The two-reader shape means "artifact metadata is converted at ingestion" is only half-true: any FUTURE retired key on the five security collections whose value a consumer does read would diverge between the two copies, silently, with the failure landing at whatever seam re-validates (e.g. a Studio re-save through saveMetaItem, which rejects with the current schema). One policy, one funnel would mean AppPlugin's bundle path either consumes applyArtifactForwardConversions (now exported from @objectstack/metadata-core, spec-only dependency) or stops duplicating the registration that MetadataPlugin already performs on the same boot (route-ownership question — one route, one owner).

Dedup: targeted search for this shape returned zero with a positive control hitting (#12772 family found), so no twin exists as of filing.

Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions