Add operational docs for release workflow

This commit is contained in:
server
2026-04-14 12:34:07 +02:00
parent cc1e4af651
commit 521f884b85
4 changed files with 226 additions and 0 deletions

View File

@@ -187,3 +187,6 @@ See [docs/format.md](docs/format.md) and
[docs/client-integration.md](docs/client-integration.md).
For Codex and Claude Code MCP setup, see [docs/agent-setup.md](docs/agent-setup.md).
For the runtime key payload contract, see [docs/launcher-contract.md](docs/launcher-contract.md).
For release steps, see [docs/release-workflow.md](docs/release-workflow.md).
For key rotation policy, see [docs/key-rotation.md](docs/key-rotation.md).
For legacy pack migration, see [docs/migration.md](docs/migration.md).

72
docs/key-rotation.md Normal file
View File

@@ -0,0 +1,72 @@
# Key rotation
`m2pack-secure` supports archive-level `key_id` so releases can move away from a
single permanent content key.
## Why rotate
Rotate when:
- a content key may have leaked
- a signing key may have leaked
- you want to expire old launcher material
- you want to separate major release lines
- you change pack validation or loader policy
## Current model
- each archive stores a `key_id` in its header
- the client chooses the verifier public key by `key_id`
- the runtime master key must be delivered with the same `key_id`
- `.m2p` loading fails if the archive `key_id` and runtime `key_id` do not match
## Recommended policy
- keep `key_id` monotonic
- reserve one `key_id` per release line or rotation event
- never reuse an old `key_id` for different secret material
- keep old public verification keys only as long as you need to support those releases
- remove stale keys from the client once old archives are no longer supported
## Rotation procedure
1. Generate a new `master.key`.
2. Generate a new signing keypair if needed.
3. Assign a new `key_id`.
4. Rebuild archives with `--key-id <new-id>`.
5. Export a new `M2PackKeys.h` for the client.
6. Export a new runtime key payload for the launcher.
7. Ship client, launcher, and `.m2p` together.
8. Retire old runtime material after rollout is complete.
## Example
```bash
./build/m2pack keygen --out-dir keys-2026-05
./build/m2pack build \
--input /srv/build/client-root \
--output out/root.m2p \
--key keys-2026-05/master.key \
--sign-secret-key keys-2026-05/signing.key \
--key-id 4
./build/m2pack export-client-config \
--key keys-2026-05/master.key \
--public-key keys-2026-05/signing.pub \
--key-id 4 \
--output /path/to/m2dev-client-src/src/PackLib/M2PackKeys.h
./build/m2pack export-runtime-key \
--key keys-2026-05/master.key \
--public-key keys-2026-05/signing.pub \
--key-id 4 \
--format blob \
--output out/runtime-key.bin
```
## Operational note
If you need overlapping support for multiple release lines, extend the client
header with multiple verifier slots and keep launcher delivery strict: one
runtime master key per active process, matching the archive `key_id`.

65
docs/migration.md Normal file
View File

@@ -0,0 +1,65 @@
# Migration from legacy packs
This project is meant to replace legacy `.pck` or EterPack-style content
delivery gradually, not through a single risky cutover.
## Target state
- Linux builds produce `.m2p`
- the client loads `.m2p` first
- runtime master key delivery is required
- silent fallback to legacy packs is disabled in production
## Suggested migration phases
### Phase 1: parallel loader
- keep the legacy loader in the client
- add `.m2p` support beside it
- verify the new loader against real content sets
- keep fallback only in development if needed
### Phase 2: pipeline validation
- build `.m2p` from the same source tree as legacy packs
- run `verify` for every archive
- run `diff` between the source tree and `.m2p`
- compare in-game behavior between legacy and `.m2p`
### Phase 3: runtime delivery
- stop embedding a real content key in the client
- deliver the runtime key through launcher, environment, or mapping
- verify startup failure behavior when the runtime key is missing
### Phase 4: production cutover
- package only `.m2p` for release clients
- disable silent fallback to legacy packs
- remove stale pack generation from release CI
- keep extract/debug tools only for internal use
## Recommended checks
- duplicate normalized paths
- invalid relative paths
- case-collision problems on Windows
- decompression failures
- manifest signature failures
- key mismatch by `key_id`
## Practical migration loop
1. Pick one legacy pack group.
2. Rebuild it as `.m2p`.
3. Verify it.
4. Diff it against the source tree.
5. Boot the client with runtime keys.
6. Validate asset loads in logs and in-game.
7. Move to the next pack group.
## Risk notes
- Do not mix silent fallback with production security claims.
- Do not ship a client that accepts `.m2p` without runtime key enforcement.
- Do not keep real secret keys inside the repository.

86
docs/release-workflow.md Normal file
View File

@@ -0,0 +1,86 @@
# Release workflow
This is the recommended end-to-end release flow for `m2pack-secure`.
The goal is to keep archive creation on Linux, keep signing keys off developer
workstations when possible, and make the Windows client consume only runtime
delivery material.
## Inputs
- client asset tree
- `master.key`
- `signing.key`
- `signing.pub`
- target `key_id`
## Output artifacts
- one or more `.m2p` archives
- generated `M2PackKeys.h`
- runtime key payload for the launcher
- release manifest and validation logs
## Minimal release flow
1. Generate or select the active content key set.
2. Build the archive with the intended `key_id`.
3. Verify the archive with the signing public key and content key.
4. Diff the archive against the source tree to catch packing mistakes.
5. Export `M2PackKeys.h` for the client source tree.
6. Export the runtime key payload for the launcher.
7. Build the Windows client against the generated header.
8. Ship `.m2p` plus the client and launcher together.
## Example
```bash
./build/m2pack build \
--input /srv/build/client-root \
--output out/root.m2p \
--key keys/master.key \
--sign-secret-key keys/signing.key \
--key-id 3 \
--json
./build/m2pack verify \
--archive out/root.m2p \
--public-key keys/signing.pub \
--key keys/master.key \
--json
./build/m2pack diff \
--left /srv/build/client-root \
--right out/root.m2p \
--json
./build/m2pack export-client-config \
--key keys/master.key \
--public-key keys/signing.pub \
--key-id 3 \
--output /path/to/m2dev-client-src/src/PackLib/M2PackKeys.h \
--json
./build/m2pack export-runtime-key \
--key keys/master.key \
--public-key keys/signing.pub \
--key-id 3 \
--format json \
--output out/runtime-key.json \
--json
```
## CI recommendations
- Run archive builds on Linux only.
- Keep `signing.key` in CI secrets or on a dedicated release box.
- Treat `master.key` as release secret material, not as source code.
- Archive and retain `verify` and `diff` outputs for each release.
- Fail the pipeline if `verify` fails or `diff` reports unexpected changes.
## Production posture
- The client should embed only verifier material and metadata.
- The launcher should provide the runtime master key.
- If `.m2p` exists and runtime key delivery fails, startup should fail hard.
- Do not silently fall back to legacy packs in production.