Files
server-deploy/docs/superpowers/plans/package-verifier-brief.md

3.8 KiB

Package verifier worker requirements

Implement ONLY internal/appbundle/*.go and optional internal/appbundle/README.md in G:/Works/server-deploy. No commits, no other files, no subagents, no production access. Use apply_patch, tests first. Parent handles CLI, shared decoder, environment inspection and integration review.

API: Verify(directory, expectedDigest string) (Verified, error). Verified: Manifest Manifest, Files map[string][]byte, Digest string. Manifest JSON fields (all required, no extras): protocolVersion (1), appId (lowercase ID), version (numeric x.y.z), runtime (compose), entrypoint (relative path to listed file), platforms ([]string of linux/amd64 or linux/arm64, unique, nonempty), components ([]Component), files ([]File). Component fields: name (lowercase ID), image (lowercase repository@sha256:64hex; no tag, port, whitespace or shell syntax in initial subset). Components 1..32, names unique; repository components use lowercase ASCII alnum with separators dot/underscore/hyphen, slash between components, no empty segments. File fields: path (portable relative slash path), digest (sha256:64 lowercase hex). Files 1..128, unique; manifest.json itself excluded from files. No slash root, drive, backslash, colon, dot/dotdot segments, dotfiles, empty segments, trailing spaces/dots, Windows device-name segments (including extensions), or case-colliding names. Allowed path segment alphabet lowercase ASCII a-z0-9 underscore hyphen dot, first character alphanumeric. Max path 240 bytes, segment 100. ID rules consistent with planner: first a-z, remaining a-z0-9-, max48.

Manifest file name manifest.json; maximum 1MiB. ExpectedDigest pins SHA-256 of the exact raw manifest bytes (manifest pins every file). Validate digest before parsing. Use shared server-deploy/internal/wire.Decode(io.Reader, target, int64 limit) being implemented by parent; it rejects duplicate/unknown/missing/case-alias fields, nulls including slice elements, trailing data and oversized input.

Read only regular files under os.Root, reject symlinks including intermediate directory links, file size max4MiB, total payload <=16MiB. Exact inventory: reject any unlisted files, secrets, symlinks, special files or unnecessary directories; allow only parent directories of declared files plus manifest.json. Bound enumeration to declared inventory rather than unbounded walk; reject extras immediately. No extraction, writes, processes, network or arbitrary command execution. Require absolute directory; staging root is caller-selected trusted directory (ancestors trusted), don't claim hostile concurrent mutation is fully prevented. Return verified bytes for later consumers; do not reopen files to execute anything.

Entrypoint must be listed. DO NOT claim Compose semantics safe/validated: contents are authenticated as bytes only. Signature trust store and executable policy come later; expected hash is a caller trust anchor, not publisher authentication. Do not hardcode live app image hashes or fetch versions.

Tests with real temp directories: valid two-component package, wrong manifest digest, changed/missing/extra file, nested valid file, symlink/intermediate symlink (skip only missing Windows privilege, Linux tested by parent), traversal, duplicate components/file paths, unpinned image, unsupported protocol/runtime/platform, missing/unknown/null component fields, oversized payload, entrypoint missing. Fixture hashes may be calculated from known test bytes, but test expected acceptance/rejection independently.

Toolchain: C:/Users/Joywayer/AppData/Local/Temp/server-deploy-go-d67bef26e1ee49718e2b62311429f729/go/bin/go.exe. Set GOCACHE to a dedicated temp path if needed. Parent creates wire shortly; don't change it to unblock. Report test results and changed paths, plus any blockers/concerns, without declaring full deployment readiness.