docs: add metin release cli plan

This commit is contained in:
root
2026-04-14 18:30:43 +02:00
parent 3f8acfc597
commit 0526ac2ef9

View File

@@ -0,0 +1,466 @@
# metin-release-cli plan
Plan for a release orchestration toolchain that stays outside NewERP and lets
the ERP module act only as the control plane.
## Goal
Build two components:
- `metin-release-cli` as the real operator and automation entry point
- `metin-release-mcp` as a thin MCP wrapper over the CLI
The ERP module should not own manifest generation, signing, blob publishing, or
launcher packaging logic. It should call the CLI through a stable contract and
store release metadata, status, logs, and audit trail.
## Why this split
Current release concerns already live across multiple repos and runtimes:
- `metin-launcher` consumes signed `manifest.json` + blob storage
- `m2dev-client` already has `make-manifest.py` and `sign-manifest.py`
- `m2pack-secure` owns `.m2p` build, verify, diff, and runtime-key export
- launcher self-update currently depends on Velopack packaging, which is still
Windows-host constrained
Putting that logic into NewERP would duplicate the release path and make the ERP
module too heavy. The CLI should own the workflow. ERP should orchestrate it.
## Design principles
- CLI first. Every real operation must be runnable without MCP.
- JSON first. Every non-interactive CLI command must support machine-readable
output.
- Thin wrapper. MCP must call CLI commands, parse JSON, and return it. No
duplicated business logic.
- Explicit state. Releases move through named stages and emit durable logs.
- Secret isolation. Signing keys and content keys stay on the release machine or
in a secret store, never in ERP DB.
- Linux-first. Manifest build, signing, blob publish, and `.m2p` validation must
run on Linux. Windows-only launcher packaging remains a separate step.
## Scope
`metin-release-cli` should cover:
- create and validate a release workspace
- build or import a release manifest
- sign the manifest
- diff against the currently published release
- upload missing blobs to the update storage
- archive historical manifests
- promote a release to current
- verify the public endpoint after publish
- optionally record release metadata in ERP through HTTP API
- optionally manage `.m2p` release artifacts and runtime-key export
- optionally run launcher publish as a separate command
`metin-release-mcp` should cover:
- expose the same operations as MCP tools
- map tool input to CLI flags
- read CLI JSON output
- pass through logs, status, and errors in structured form
## Non-goals
- No manifest generation inside ERP PHP code
- No signing inside ERP
- No heavy artifact proxying through ERP uploads for multi-GB releases
- No duplicated publish logic in MCP
- No attempt to hide Windows constraints for Velopack launcher packaging
## Canonical release path
For the current launcher contract, the canonical asset release path is:
1. obtain a prepared client root on Linux
2. generate `manifest.json`
3. sign `manifest.json`
4. compute which content-addressed blobs are missing remotely
5. upload missing blobs
6. upload archived manifest under `manifests/<version>.json`
7. upload archived signature under `manifests/<version>.json.sig`
8. switch top-level `manifest.json` and `manifest.json.sig`
9. verify the public endpoint
10. report final release metadata to ERP
For launcher self-update, the path is separate:
1. build win-x64 launcher package on Windows-capable host
2. publish Velopack feed into `/launcher/`
3. optionally annotate the same release in ERP
## Proposed architecture
### 1. metin-release-cli
Suggested implementation language:
- Python is the pragmatic default because the current manifest tooling already
exists in Python
- shell scripts may wrap platform-specific steps, but the primary interface
should be one CLI executable with stable subcommands
Suggested internal modules:
- `workspace`
- resolve source roots, temp dirs, release output dirs
- `manifest`
- call or absorb `make-manifest.py`
- `signing`
- call or absorb `sign-manifest.py`
- `storage`
- remote existence checks
- blob upload
- manifest archive upload
- current manifest promotion
- `verify`
- verify local artifacts
- verify public HTTP endpoint
- `erp`
- create/update release records in ERP
- `m2pack`
- optional integration with `m2pack-secure`
- `launcher`
- optional launcher publish integration
### 2. metin-release-mcp
Suggested shape:
- one MCP server process
- each tool maps 1:1 to one CLI subcommand
- wrapper only:
- validates tool input
- spawns CLI
- parses JSON stdout
- returns structured result
- forwards stderr as diagnostic text
No release decision logic should live here.
## Release state model
The CLI should emit explicit states the ERP module can mirror:
- `draft`
- `scanning`
- `manifest_built`
- `signed`
- `uploading_blobs`
- `uploaded`
- `promoting`
- `published`
- `verifying`
- `verified`
- `failed`
- `rolled_back`
Each state transition should include:
- `release_id` if known in ERP
- `version`
- `started_at`
- `finished_at`
- `duration_ms`
- `step`
- `status`
- `message`
- `log_path` if available
## CLI command set
Suggested commands:
### Release lifecycle
- `metin-release release init`
- create local workspace metadata for a new version
- `metin-release release inspect`
- inspect source root, file counts, launcher presence, total bytes
- `metin-release release build-manifest`
- generate canonical `manifest.json`
- `metin-release release sign`
- sign `manifest.json`
- `metin-release release diff-remote`
- compare manifest blobs against remote storage
- `metin-release release upload-blobs`
- upload only missing blobs
- `metin-release release upload-manifest-archive`
- upload `manifests/<version>.json` and `.sig`
- `metin-release release promote`
- switch current `manifest.json` and `.sig`
- `metin-release release verify-public`
- fetch public manifest, signature, and optional blob samples
- `metin-release release publish`
- composite command executing the full asset publish flow
- `metin-release release rollback`
- promote a historical manifest back to current
### ERP sync
- `metin-release erp create-release`
- `metin-release erp update-release`
- `metin-release erp append-log`
- `metin-release erp mark-status`
### m2pack integration
- `metin-release m2pack build`
- `metin-release m2pack verify`
- `metin-release m2pack diff`
- `metin-release m2pack export-runtime-key`
### Launcher integration
- `metin-release launcher publish`
- separate path because of Windows packaging constraints
## JSON contract
Every automation-facing command should support:
```text
--json
```
Success output shape:
```json
{
"ok": true,
"command": "release publish",
"version": "2026.04.14-1",
"status": "published",
"artifacts": {
"manifest_path": "/abs/path/manifest.json",
"signature_path": "/abs/path/manifest.json.sig"
},
"stats": {
"file_count": 123,
"blob_count": 9,
"uploaded_blob_count": 3,
"uploaded_bytes": 1048576
},
"remote": {
"manifest_url": "https://updates.jakubkadlec.dev/manifest.json"
},
"erp": {
"release_id": 42
}
}
```
Failure output shape:
```json
{
"ok": false,
"command": "release publish",
"version": "2026.04.14-1",
"status": "failed",
"error": {
"code": "blob_upload_failed",
"message": "Failed to upload one or more blobs"
}
}
```
Exit code rules:
- `0` success
- `1` operator or validation error
- `2` remote or network error
- `3` signing or integrity error
- `4` ERP sync error
## ERP integration contract
The ERP module should integrate with the CLI at the orchestration layer only.
Recommended boundary:
- ERP creates a draft release record
- ERP stores operator intent, notes, target channel, and visibility
- ERP triggers the CLI through a worker, SSH command, queue job, or agent
- CLI performs release operations
- CLI pushes structured status updates back to ERP
- ERP renders the timeline, logs, artifacts, and rollback actions
Recommended ERP-owned data:
- release version
- notes
- previous release reference
- publish status
- operator identity
- started/finished timestamps
- manifest metadata
- remote verification status
- launcher publish status
- pointers to logs and artifacts
CLI-owned data:
- actual manifest generation
- signing
- file hashing
- blob deduplication
- upload semantics
- runtime-key export
- launcher packaging invocation
## Remote storage contract
For the current launcher path, the CLI should treat this as canonical:
- `/var/www/updates.jakubkadlec.dev/files/<hash-prefix>/<sha256>`
- `/var/www/updates.jakubkadlec.dev/manifests/<version>.json`
- `/var/www/updates.jakubkadlec.dev/manifests/<version>.json.sig`
- `/var/www/updates.jakubkadlec.dev/manifest.json`
- `/var/www/updates.jakubkadlec.dev/manifest.json.sig`
- `/var/www/updates.jakubkadlec.dev/launcher/*`
Promotion safety rule:
- upload immutable blobs first
- upload archived versioned manifest second
- replace current manifest last
## Secrets and security
- launcher manifest signing key remains outside ERP
- `.m2p` master keys remain outside ERP
- CLI reads secrets from:
- fixed secure file paths
- environment variables
- secret manager integration later
- CLI must redact secrets from logs and JSON output
Never return:
- raw private keys
- runtime master keys
- decrypted secret material
## Linux and Wine posture
Supported on Linux now:
- client tree scan
- manifest build
- manifest signing
- blob upload and promotion
- `.m2p` build and verification
- Wine-based smoke validation if needed
Not fully Linux-native yet:
- Velopack packaging for win-x64 launcher release
Implication:
- asset release commands should be Linux-first
- launcher publish should remain an explicit separate command and may require a
Windows runner or Windows host until the toolchain changes
## MCP tool set
Suggested MCP tools:
- `release_init`
- `release_inspect`
- `release_build_manifest`
- `release_sign`
- `release_diff_remote`
- `release_upload_blobs`
- `release_promote`
- `release_verify_public`
- `release_publish`
- `release_rollback`
- `erp_create_release`
- `erp_update_release`
- `m2pack_build`
- `m2pack_verify`
- `m2pack_diff`
- `m2pack_export_runtime_key`
- `launcher_publish`
Each tool should document the exact CLI command it runs.
## Recommended implementation phases
### Phase 1. Asset release CLI
Build first:
- `release inspect`
- `release build-manifest`
- `release sign`
- `release diff-remote`
- `release upload-blobs`
- `release promote`
- `release verify-public`
- `release publish`
This is the minimum path ERP needs for the current launcher contract.
### Phase 2. ERP sync
Build second:
- `erp create-release`
- `erp update-release`
- CLI status callbacks or polling contract
This lets the ERP module focus on UI, permissions, and audit trail.
### Phase 3. MCP wrapper
Build third:
- expose the Phase 1 and 2 CLI commands as MCP tools
- no new logic
### Phase 4. m2pack path
Build fourth:
- `m2pack build`
- `m2pack verify`
- `m2pack diff`
- `m2pack export-runtime-key`
Only after the signed-manifest release path is stable.
### Phase 5. Launcher release path
Build fifth:
- `launcher publish`
- Windows-capable execution environment
- optional ERP annotation
## Open decisions
- Whether the CLI should directly push status to ERP or ERP should poll CLI job
results
- Whether release workspaces are local-only or persisted on a shared release
host
- Whether `.m2p` artifacts become part of the same release object now or later
- Whether launcher release should be represented as:
- separate release type
- or a child job under the same release
## Recommendation
Start with:
- one Linux-first `metin-release-cli`
- one thin `metin-release-mcp`
- ERP module consuming only CLI results and statuses
Do not start by embedding release logic in ERP. That will create a second
source of truth and make later `.m2p` and launcher evolution harder.