This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user