Dependency pinning
🛡️ Step 1 — Dependency pinning
Section titled “🛡️ Step 1 — Dependency pinning”🎯 Goal
Section titled “🎯 Goal”Ensure that every compilation of SONAR relies on a strictly determined, reproducible and auditable set of dependencies, regardless of:
- the build machine
- network connectivity
- the moment of compilation
Without this step:
- the build is not deterministic
- the chain of trust is broken
- the (Cosign) signature loses its value
📦 Scope
Section titled “📦 Scope”Pinning covers:
- Rust dependencies (direct + transitive)
- Deno dependencies (remote modules)
- version resolution
- dependency sources
- build configuration
🔐 Mandatory rules
Section titled “🔐 Mandatory rules”1. Mandatory Rust lockfile
Section titled “1. Mandatory Rust lockfile”The Cargo.lock file must:
- be present
- be versioned
- never be modified implicitly
- not contain ’^’ in version numbers
all versions are fixed (no ^, no ~) → so no automatic supply-chain drift
cargo build --lockedRecommended strict mode:
cargo build --frozen2. No dynamic resolution
Section titled “2. No dynamic resolution”Every compilation must be:
- without network access
- without implicit updates
👉 Any download attempt must fail the build
3. Controlled dependency updates
Section titled “3. Controlled dependency updates”Updates must be:
- explicit (
cargo update) - traced (dedicated commit)
- validated (review)
- tested offline
🦀 Rust — Implementation
Section titled “🦀 Rust — Implementation”Generating the lockfile
Section titled “Generating the lockfile”cargo generate-lockfilePrefetching dependencies
Section titled “Prefetching dependencies”cargo fetch --lockedVendoring (mandatory for offline)
Section titled “Vendoring (mandatory for offline)”cargo vendor vendor > .cargo/config.tomlExpected configuration
Section titled “Expected configuration”[source.crates-io]replace-with = "vendored-sources"
[source.vendored-sources]directory = "vendor"Secure build
Section titled “Secure build”cargo build --frozen🟡 Deno — Implementation
Section titled “🟡 Deno — Implementation”Generating the lockfile
Section titled “Generating the lockfile”Create the deno.json file with the following elements:
{ "vendor": true, "lock": { "frozen": true }, "nodeModulesDir": "auto"}so: vendor: true → you cache dependencies locally → excellent for air-gapped lock.frozen: true → you prevent any dependency drift → very good
Prefetching the cache
Section titled “Prefetching the cache”set DENO_DIR=.deno-cachedeno cache deno.jsondeno install —frozen
Section titled “deno install —frozen”⚠️ Deno constraints
Section titled “⚠️ Deno constraints”The build must:
- contain no unpinned dynamic import
- never trigger an implicit download
📁 Artifacts to version
Section titled “📁 Artifacts to version”Mandatory in the repository:
Cargo.lock.cargo/config.tomlvendor/deno.lockdeno.json
❌ Prohibitions
Section titled “❌ Prohibitions”- deleting
Cargo.lock - building without
--lockedor--frozen - depending on non-vendored crates
- using Deno without
--cached-only - importing unpinned dynamic dependencies
✅ Validation criteria
Section titled “✅ Validation criteria”The step is validated if:
- build succeeds without network
- no download attempt
cargo build --frozenpasses- no modification of
Cargo.lockduring the build
🔄 Update workflow
Section titled “🔄 Update workflow”🧠 Architecture decision
Section titled “🧠 Architecture decision”Chosen option:
➡️ Targeted vendoring (cargo vendor)
Reasons:
- simpler to audit
- reproducible
- compatible with strict offline
- no need for a crates.io mirror
🔐 Security impact
Section titled “🔐 Security impact”This step guarantees:
- build reproducibility
- dependency traceability
- resistance to supply-chain attacks
- a reliable basis for Cosign signing
🔎 Checkpoints
Section titled “🔎 Checkpoints”Before the next step:
- Cargo.lock frozen
- vendor present
- config.toml valid
- deno.lock present
- Deno cache generated
- offline build validated
➡️ Next step
Section titled “➡️ Next step”👉 Step 2 — Freezing the build environment (toolchain & OS)