111 lines
3.9 KiB
Markdown
111 lines
3.9 KiB
Markdown
# 29 — Package integrity and canonicalization
|
|
|
|
## Purpose
|
|
|
|
Digest behavior must be identical across Windows, Linux and macOS and must not depend on YAML formatting, archive order or local filesystem metadata.
|
|
|
|
## Text normalization
|
|
|
|
For every declared text file:
|
|
|
|
1. reject invalid UTF-8;
|
|
2. remove a UTF-8 BOM;
|
|
3. normalize Unicode to NFC;
|
|
4. convert CRLF and CR to LF;
|
|
5. remove trailing spaces and tabs from every line;
|
|
6. preserve intentional internal blank lines;
|
|
7. end with exactly one LF.
|
|
|
|
Binary resources are not text-normalized.
|
|
|
|
## Manifest canonicalization
|
|
|
|
- Parse `playbook.yaml` using safe YAML parsing.
|
|
- Reject duplicate mapping keys, custom tags, non-finite numbers and YAML values that cannot be represented as JSON.
|
|
- Apply schema-defined semantic defaults in one versioned normalization function.
|
|
- Convert the result to JSON-compatible values.
|
|
- Serialize using RFC 8785 JSON Canonicalization Scheme.
|
|
|
|
YAML comments and key order do not affect the digest.
|
|
|
|
## Package file inventory
|
|
|
|
`package.files` is authoritative.
|
|
|
|
- Every listed file must exist as a regular file below the package root.
|
|
- Every package file other than `playbook.yaml` must be listed.
|
|
- Directories, symlinks, hardlinks, device files and executables are rejected.
|
|
- Paths are slash-separated, relative, normalized and unique.
|
|
- The main template and all partials must have the appropriate declared role.
|
|
- Evaluation and example IDs must match the package metadata and quality references.
|
|
|
|
## Package digest payload
|
|
|
|
Construct this logical object:
|
|
|
|
```json
|
|
{
|
|
"algorithm": "devrunbook-package-v1",
|
|
"manifest": "<canonical JSON object, not a string>",
|
|
"files": [
|
|
{
|
|
"path": "CHANGELOG.md",
|
|
"role": "changelog",
|
|
"sizeBytes": 123,
|
|
"sha256": "..."
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Include only files with `digest: true`, sorted by UTF-8 path bytes. File SHA-256 is computed over normalized text bytes or original binary bytes. Serialize the payload with RFC 8785 and SHA-256 the resulting UTF-8 bytes.
|
|
|
|
Changing any digested file changes the package digest and therefore requires a new published version.
|
|
|
|
## Render digest
|
|
|
|
The render digest is SHA-256 over the exact final prompt bytes after platform composition:
|
|
|
|
- UTF-8;
|
|
- NFC;
|
|
- LF endings;
|
|
- stable headings and list formatting;
|
|
- exactly one final LF;
|
|
- no generation timestamp inside the prompt unless declared as an input.
|
|
|
|
## Repository Profile digest
|
|
|
|
Parse and validate the profile, remove `metadata.contentDigest`, apply normalized ordering/defaults, serialize using RFC 8785 and SHA-256 the canonical bytes. The stored `contentDigest` must match on import.
|
|
|
|
## Run Pack manifest digest
|
|
|
|
1. Build `manifest.json` with every exported file except `manifest.json` itself.
|
|
2. Compute each file size and SHA-256 from the exact archive payload bytes.
|
|
3. Omit the `manifestDigest` property.
|
|
4. Serialize the remaining manifest with RFC 8785.
|
|
5. Compute SHA-256 and set the lowercase hex result as `manifestDigest`.
|
|
6. Write the final manifest as pretty JSON with LF endings. Pretty formatting does not define the digest; canonical JSON with the field omitted does.
|
|
|
|
## Archive construction
|
|
|
|
- Paths sorted lexicographically by UTF-8 bytes.
|
|
- Fixed permission bits for regular files.
|
|
- Fixed archive timestamps, preferably the ZIP epoch supported by the library.
|
|
- No extra fields containing local user, host or filesystem metadata.
|
|
- Compression level may differ without affecting file or manifest digests.
|
|
- Archive-level SHA-256 may be stored as artifact metadata but is not part of `manifest.json`.
|
|
|
|
## Verification
|
|
|
|
Import verifies in this order:
|
|
|
|
1. archive limits and path safety;
|
|
2. manifest schema;
|
|
3. exact file set—no missing or undeclared files;
|
|
4. file sizes and hashes;
|
|
5. manifest digest;
|
|
6. package/profile schema and semantic validation;
|
|
7. historical render digest where a rendered prompt is present.
|
|
|
|
Any failure rejects the import atomically with a path-specific error.
|