Skip to content

Bind missing promotion metadata to admitted parent #1062

Description

@bcdonadio

Observed behavior: The promote metadata creation path treats a pathname-based bounded-reader ENOENT as an authenticated absence. If its admitted project directory A is temporarily replaced by a same-owner private directory B without meta.json, the read can observe B's absence. Restoring A before the writer lets the existing parent assertions succeed and replaces A's original metadata with only cwd and lastPromote, dropping existing keys.

Expected behavior: Metadata creation must use absence evidence bound to the retained admitted parent. A transient replacement must not convert another directory's absence into permission to overwrite existing metadata in the admitted directory.

Root cause: readBoundedRegularFileWithStat can return parent identity on successful reads, but throws an ordinary ENOENT without parent provenance on absence. Revalidating the pathname after the original directory is restored does not prove where absence was observed. A descriptor-relative read/creation contract or equivalent authenticated absence evidence is needed.

How to reproduce safely: In an owner-only synthetic fixture, retain a handle to private directory A containing metadata with an extra key. In a test-only bounded-reader wrapper, rename A aside, put private directory B without metadata at the path, invoke the real bounded reader and retain its ENOENT, restore A, then rethrow that error into the promote route. The route's missing-file branch creates metadata, and the extra key in A is lost. This report is static source validation of that deterministic sequence, not an operational attack or a claimed executed exploit. Do not use live HOME, daemon data, locks, or credentials.

Evidence: Discovered during Bug #948, PR #1061 round-2 review at 9145ac755d26f30573bc3024c078a89cb3ac7598, src/daemon/routes/promote.ts missing-file branch (lines 355-357) and src/security-files.ts bounded-reader return/error contract. Opus second-pass independently validated; owner accepts P2 based on same-UID, owner-private directory prerequisite and metadata-only integrity impact. No privilege escalation, disclosure, or database corruption is demonstrated.

This is distinct from #948's existing-file read-parent comparison and #964's ancestor-chain admission. It is a newly discovered follow-up outside frozen campaign S3; no native campaign parent should be attached. No shared-reader redesign is required in PR #1061.

Environment:

  • Agent: Codex Astra owner, Opus 5 medium second-pass reviewer
  • Connector: static repository review and synthetic test design
  • OS: Fedora Linux

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    Priority

    Medium

    Effort

    None yet

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions