harn_cli/cli/pack.rs
1use std::path::PathBuf;
2
3use clap::{Args, Subcommand};
4
5#[derive(Debug, Args)]
6#[command(arg_required_else_help = true)]
7pub struct PackArgs {
8 #[command(subcommand)]
9 pub command: Option<PackCommand>,
10
11 /// Entrypoint `.harn` file to pack. Transitive Harn modules and
12 /// non-Harn assets referenced by import directives under the
13 /// entrypoint's directory are bundled alongside it.
14 ///
15 /// When `harn pack` is invoked without a subcommand, this positional
16 /// argument selects the build path; passing a subcommand (e.g.
17 /// `harn pack verify <bundle>`) routes to that subcommand instead.
18 #[arg(required = false)]
19 pub entrypoint: Option<PathBuf>,
20
21 /// Output `.harnpack` path. Defaults to the entrypoint stem with
22 /// the `.harnpack` extension next to the entrypoint.
23 #[arg(long, value_name = "PATH")]
24 pub out: Option<PathBuf>,
25
26 /// Read an existing `.harnpack` and re-emit it under the v2
27 /// manifest, preserving the prior bundle's id, name, version,
28 /// triggers, workflow graph, and prompt capsules. The new
29 /// `<entrypoint>` argument supplies the transitive-modules /
30 /// SBOM payload that v1 lacked.
31 #[arg(long, value_name = "OLD_BUNDLE")]
32 pub upgrade: Option<PathBuf>,
33
34 /// Sign the bundle hash and embed an Ed25519 signature in the manifest.
35 #[arg(
36 long,
37 default_value_t = false,
38 conflicts_with = "unsigned",
39 requires = "key"
40 )]
41 pub sign: bool,
42
43 /// Ed25519 private key PEM used with `--sign`.
44 #[arg(long, value_name = "PATH", requires = "sign")]
45 pub key: Option<PathBuf>,
46
47 /// Mark the bundle as unsigned. This still emits an OpenTrustGraph
48 /// release record at autonomy tier `suggest`.
49 #[arg(long, default_value_t = false)]
50 pub unsigned: bool,
51
52 /// Refuse to bundle modules whose path matches a built-in
53 /// secret-bearing glob (`.env`, `.env.*`, `*.pem`, `*.key`,
54 /// `credentials*`, anything under `secrets/`). The default behavior
55 /// matches the historical pack semantics: pack the full transitive
56 /// module set without any secret filtering. Pass `--exclude-secrets`
57 /// from CI or release pipelines that share bundles externally.
58 ///
59 /// The same gate skips imported non-Harn assets that match the
60 /// secret heuristic and reports each skipped asset as a structured
61 /// JSON warning plus `manifest.metadata.skipped_assets`.
62 #[arg(long, default_value_t = false, conflicts_with = "include_secrets")]
63 pub exclude_secrets: bool,
64
65 /// Explicitly opt in to the default behavior: bundle every
66 /// transitive module without secret filtering. Useful in scripts
67 /// that want to be explicit about the bundle's contents instead of
68 /// relying on the default.
69 #[arg(long, default_value_t = false)]
70 pub include_secrets: bool,
71
72 /// Emit a `JsonEnvelope` summary instead of a human-readable
73 /// one-liner. Schema: `harn --json-schemas --command pack`.
74 #[arg(long, default_value_t = false)]
75 pub json: bool,
76}
77
78#[derive(Debug, Subcommand)]
79pub enum PackCommand {
80 /// Verify a `.harnpack` bundle: check the embedded Ed25519
81 /// signature (if present), recompute the canonical bundle hash,
82 /// and compare each archive entry's BLAKE3 against the manifest's
83 /// recorded hashes. Exits non-zero on any mismatch.
84 Verify(PackVerifyArgs),
85}
86
87#[derive(Debug, Args)]
88#[command(arg_required_else_help = true)]
89pub struct PackVerifyArgs {
90 /// Path to the `.harnpack` archive to verify.
91 pub bundle: PathBuf,
92
93 /// Accept bundles that carry no Ed25519 signature. Without this
94 /// flag, an unsigned bundle is treated as a verification failure.
95 #[arg(long, default_value_t = false)]
96 pub allow_unsigned: bool,
97
98 /// JSON trust policy describing the signer registry URL and
99 /// optional trusted signer allowlist to enforce during
100 /// verification.
101 #[arg(long, value_name = "PATH")]
102 pub trust_policy: Option<PathBuf>,
103
104 /// Require the bundle signer to resolve from the trusted signer
105 /// registry and, when `--trust-policy` supplies a
106 /// `trusted_signers` allowlist, appear in that allowlist too.
107 #[arg(long, default_value_t = false)]
108 pub require_trusted_signer: bool,
109
110 /// Cross-check SBOM package hashes against the archive payloads
111 /// they describe when the bundle format carries a corresponding
112 /// entry.
113 #[arg(long, default_value_t = false)]
114 pub strict: bool,
115
116 /// Emit a `JsonEnvelope` summary instead of a human-readable
117 /// one-liner. Schema: `harn --json-schemas --command "pack verify"`.
118 #[arg(long, default_value_t = false)]
119 pub json: bool,
120}