Skip to content

Commit 3fe3b13

Browse files
fix: format debt, GitLab CI wiring, and the (never-actually-run) live-download install path (#71)
Three items from the sitrep backlog, done as five separate commits. The last two turned into a real chain of discovery — wiring a CI job to exercise the live-download path surfaced that `opsm runtime install` has, as far as I can tell, **never actually completed a real install against a real nickel binary**, for three independent reasons stacked on top of each other. ## 1. `style: run mix format across the tree` (`ef87e0b`) 226 files were unformatted, leaving the Mustfile's `format` check permanently red with nothing enforcing it. Pure `mix format` output, no manual edits. ## 2. `fix(gitlab-ci): fix root-relative rules:exists paths` (`10588f8`) Every `mix-*`/`cargo-*` job in `.gitlab-ci.yml` was permanently dormant: `mix.exs` lives in `opsm_ex/`, and the Rust code is nine independent first-party crates (`opsm-ui/tui`, two `opsm_ex/native` NIFs, six `services/*`) — no root `Cargo.toml` for `rules: exists:` to ever match. `mix-*` jobs now target `opsm_ex/`; `cargo-*` jobs loop over a `$RUST_CRATE_DIRS` list. Verified: YAML parses, `mix format`'s own check (now green) confirms the job would pass, `just toolchain-check` passes. ## 3–5. The live-download chain Task was "add a `workflow_dispatch` job for the live-download tests" (`8d0e373`). Getting a real nickel binary onto a runner to test it locally surfaced two more bugs, both now fixed and **verified against a real 47MB zig install**: - **`fix(nickel): unbreak the entire runtime plugin corpus`** (`3f67294`) — 84 of 95 `.ncl` files failed to even typecheck against the canonical nickel 1.16.0 pinned in `opsm.toml [runtime]`. All 84 failures traced to one shared file, two bugs: `runtime-plugin.ncl` had three fields with `default` before `doc` in the annotation chain (nickel 1.16's grammar requires the reverse — confirmed via minimal repro), and every plugin destructured its import as `let { RuntimePlugin, .. } = import ...` against a module whose export is the bare contract value, not a record — the destructuring could never match. Both are one-line-per-field-or-file mechanical fixes. All 95 files now typecheck; all 94 `runtime/core/*.ncl` plugins now fully `nickel export` to JSON. - **`fix(verified-http): forward receive_timeout and :into to Req`** (`f9b926e`) — with nickel now working, the install still failed: `Opsm.Verified.Http.do_get/2` never forwarded `opts[:into]` to `Req.get/2` at all, so `Manager.download_archive/1`'s `VerifiedHttp.get(url, into: File.stream!(dest))` silently buffered the response in memory instead of streaming to disk, returned `{:ok, _}`, and `extract_archive/3` got handed a file that was never written. Also found in the same function: `do_get`/`do_post` read `opts[:timeout]`, but every call site in the codebase (~480 occurrences) passes `receive_timeout:` — Req's actual option name — so every custom timeout anywhere in OPSM has been silently discarded in favor of the 30s default. Both fixed. - **`feat(e2e): add a live-download job`** (`8d0e373`) — the actual dispatch job: Rust toolchain (pinned 1.97.0) → `cargo install nickel-lang-cli --version 1.16.0` (confirmed to exist at that version on crates.io) → `mix test integration_test.exs --include external_api --include live_download`. ## Verified (OTP 28.3.1 / Elixir 1.19.5, real `nickel-lang-cli` 1.16.0 built from source) - `mix format --check-formatted` — clean - `mix compile --warnings-as-errors` — clean - Full default suite — 807/807 - `sh scripts/toolchain.sh check` — clean - All 95 `.ncl` files nickel-typecheck; all 94 `runtime/core/*` fully export - **`mix test test/opsm/runtime/integration_test.exs --include external_api --include live_download` — 15/15, 0 failures**, with a cold cache: real download from ziglang.org, extract, `which/1`, `current_version/1`, `remove/1`, reinstall idempotency - `.gitlab-ci.yml` / `.github/workflows/e2e.yml` YAML parse clean The GitLab `cargo-*` job bodies aren't runnable in this sandbox (no GitLab remote, and installing `cargo-audit`/`cargo-deny` from crates.io for 9 crates wasn't worth the time here) — reviewed by inspection against the confirmed crate list and the already-working per-crate pattern in `nif-build.yml`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Kq24sZCEohSrNFXSuEuz6C --- _Generated by [Claude Code](https://claude.ai/code/session_01Kq24sZCEohSrNFXSuEuz6C)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent fee4046 commit 3fe3b13

313 files changed

Lines changed: 9400 additions & 5448 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/e2e.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
# Jobs:
77
# e2e-opsm — offline E2E suite (runs on every push/PR)
88
# runtime-api — runtime version API integration tests (external_api tag, no downloads)
9+
# live-download — full runtime install pipeline, incl. nickel plugin
10+
# evaluation (workflow_dispatch only, see below)
911
#
1012
# :live_download tests (full tool installs ~10-50MB) are workflow_dispatch only
1113
# to avoid burning bandwidth on every commit; run manually when validating
@@ -88,3 +90,49 @@ jobs:
8890
--include external_api \
8991
--exclude live_download \
9092
--trace
93+
live-download:
94+
name: Runtime — live install (workflow_dispatch only)
95+
if: github.event_name == 'workflow_dispatch'
96+
runs-on: ubuntu-latest
97+
timeout-minutes: 15
98+
steps:
99+
- name: Checkout
100+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
101+
- name: Install Rust toolchain (to build nickel)
102+
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
103+
with:
104+
toolchain: '1.97.0'
105+
- name: Cache cargo-installed tools
106+
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
107+
with:
108+
key: nickel-lang-cli-1.16.0
109+
- name: Install nickel
110+
# Pinned to opsm.toml [runtime] — see docs/TOOLCHAIN.adoc. Manager.install
111+
# (opsm_ex/lib/opsm/runtime/manager.ex) shells out to the `nickel` binary
112+
# to evaluate runtime/core/*.ncl plugin definitions; without it every
113+
# install fails with {:error, {:nickel_not_installed, tool}}.
114+
run: cargo install nickel-lang-cli --version 1.16.0 --locked
115+
- name: Setup Erlang/Elixir
116+
uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
117+
with:
118+
# Versions derive from opsm.toml [runtime] via .tool-versions
119+
# (generated by `just toolchain-sync` — see docs/TOOLCHAIN.adoc)
120+
version-file: '.tool-versions'
121+
version-type: 'strict'
122+
- name: Restore Mix cache
123+
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v4
124+
with:
125+
path: |
126+
opsm_ex/deps
127+
opsm_ex/_build
128+
key: ${{ runner.os }}-mix-${{ hashFiles('opsm_ex/mix.lock') }}
129+
- name: Install dependencies
130+
run: cd opsm_ex && mix deps.get
131+
- name: Compile
132+
run: cd opsm_ex && mix compile --warnings-as-errors
133+
- name: Run live-download runtime install tests (full zig install via Manager.install)
134+
run: |
135+
cd opsm_ex && mix test test/opsm/runtime/integration_test.exs \
136+
--include external_api \
137+
--include live_download \
138+
--trace

.gitlab-ci.yml

Lines changed: 130 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66
# opsm.toml [runtime] — drift is gated by `just toolchain-check`.
77
# Scanner images (trivy/semgrep/trufflehog) deliberately float: their
88
# detection databases need to stay fresh, so pinning them is worse.
9+
#
10+
# There is no root mix.exs or Cargo.toml — mix.exs lives in opsm_ex/, and
11+
# the estate's Rust code is nine independent first-party crates (the
12+
# ratatui TUI, two Elixir NIFs, and six microservices under services/).
13+
# `exists: mix.exs` / `exists: Cargo.toml` at repo root never matched
14+
# either, so every mix-*/cargo-* job below was permanently dormant.
15+
# mix-* jobs now target opsm_ex/ directly; cargo-* jobs loop over
16+
# $RUST_CRATE_DIRS. Keep that variable and each job's `rules: exists:`
17+
# list in sync when a crate is added or removed — `rules: exists:` needs
18+
# literal paths, it does not expand CI variables.
919

1020
stages:
1121
- security
@@ -14,11 +24,25 @@ stages:
1424
- build
1525
variables:
1626
CARGO_HOME: ${CI_PROJECT_DIR}/.cargo
27+
# First-party Rust crates only — opsm_ex/deps/** is vendored (Mix deps
28+
# cache), never linted/audited/built as our own code.
29+
RUST_CRATE_DIRS: >-
30+
opsm-ui/tui
31+
opsm_ex/native/opsm_pq_nif
32+
opsm_ex/native/quic_transport
33+
services/checky-monkey
34+
services/oikos
35+
services/palimpsest-license
36+
services/selur
37+
services/svalinn
38+
services/vordr
1739
cache:
1840
key: ${CI_COMMIT_REF_SLUG}
1941
paths:
2042
- .cargo/
21-
- target/
43+
- "*/target/"
44+
- "*/*/target/"
45+
- "*/*/*/target/"
2246
# ==================
2347
# Security Scanning
2448
# ==================
@@ -39,32 +63,57 @@ cargo-audit:
3963
stage: security
4064
image: rust:1.97
4165
script:
42-
- cargo install cargo-audit
43-
- cargo audit
66+
- cargo install cargo-audit --locked
67+
- |
68+
for dir in $RUST_CRATE_DIRS; do
69+
echo "== cargo audit: $dir =="
70+
(cd "$dir" && cargo audit)
71+
done
4472
rules:
4573
- exists:
46-
- Cargo.toml
74+
- opsm-ui/tui/Cargo.toml
75+
- opsm_ex/native/opsm_pq_nif/Cargo.toml
76+
- opsm_ex/native/quic_transport/Cargo.toml
77+
- services/checky-monkey/Cargo.toml
78+
- services/oikos/Cargo.toml
79+
- services/palimpsest-license/Cargo.toml
80+
- services/selur/Cargo.toml
81+
- services/svalinn/Cargo.toml
82+
- services/vordr/Cargo.toml
4783
cargo-deny:
4884
stage: security
4985
image: rust:1.97
5086
script:
51-
- cargo install cargo-deny
52-
- cargo deny check
87+
- cargo install cargo-deny --locked
88+
- |
89+
for dir in $RUST_CRATE_DIRS; do
90+
echo "== cargo deny: $dir =="
91+
(cd "$dir" && cargo deny check)
92+
done
5393
rules:
5494
- exists:
55-
- Cargo.toml
95+
- opsm-ui/tui/Cargo.toml
96+
- opsm_ex/native/opsm_pq_nif/Cargo.toml
97+
- opsm_ex/native/quic_transport/Cargo.toml
98+
- services/checky-monkey/Cargo.toml
99+
- services/oikos/Cargo.toml
100+
- services/palimpsest-license/Cargo.toml
101+
- services/selur/Cargo.toml
102+
- services/svalinn/Cargo.toml
103+
- services/vordr/Cargo.toml
56104
allow_failure: true
57105
mix-audit:
58106
stage: security
59107
image: elixir:1.19.5-otp-28
60108
script:
109+
- cd opsm_ex
61110
- mix local.hex --force
62111
- mix archive.install hex mix_audit --force
63112
- mix deps.get
64113
- mix deps.audit
65114
rules:
66115
- exists:
67-
- mix.exs
116+
- opsm_ex/mix.exs
68117
allow_failure: true
69118
# ==================
70119
# Linting
@@ -74,38 +123,64 @@ rustfmt:
74123
image: rust:1.97
75124
script:
76125
- rustup component add rustfmt
77-
- cargo fmt -- --check
126+
- |
127+
for dir in $RUST_CRATE_DIRS; do
128+
echo "== cargo fmt --check: $dir =="
129+
(cd "$dir" && cargo fmt -- --check)
130+
done
78131
rules:
79132
- exists:
80-
- Cargo.toml
133+
- opsm-ui/tui/Cargo.toml
134+
- opsm_ex/native/opsm_pq_nif/Cargo.toml
135+
- opsm_ex/native/quic_transport/Cargo.toml
136+
- services/checky-monkey/Cargo.toml
137+
- services/oikos/Cargo.toml
138+
- services/palimpsest-license/Cargo.toml
139+
- services/selur/Cargo.toml
140+
- services/svalinn/Cargo.toml
141+
- services/vordr/Cargo.toml
81142
clippy:
82143
stage: lint
83144
image: rust:1.97
84145
script:
85146
- rustup component add clippy
86-
- cargo clippy -- -D warnings
147+
- |
148+
for dir in $RUST_CRATE_DIRS; do
149+
echo "== cargo clippy: $dir =="
150+
(cd "$dir" && cargo clippy -- -D warnings)
151+
done
87152
rules:
88153
- exists:
89-
- Cargo.toml
154+
- opsm-ui/tui/Cargo.toml
155+
- opsm_ex/native/opsm_pq_nif/Cargo.toml
156+
- opsm_ex/native/quic_transport/Cargo.toml
157+
- services/checky-monkey/Cargo.toml
158+
- services/oikos/Cargo.toml
159+
- services/palimpsest-license/Cargo.toml
160+
- services/selur/Cargo.toml
161+
- services/svalinn/Cargo.toml
162+
- services/vordr/Cargo.toml
90163
allow_failure: true
91164
mix-format:
92165
stage: lint
93166
image: elixir:1.19.5-otp-28
94167
script:
168+
- cd opsm_ex
95169
- mix format --check-formatted
96170
rules:
97171
- exists:
98-
- mix.exs
172+
- opsm_ex/mix.exs
99173
credo:
100174
stage: lint
101175
image: elixir:1.19.5-otp-28
102176
script:
177+
- cd opsm_ex
103178
- mix local.hex --force
104179
- mix deps.get
105180
- mix credo --strict
106181
rules:
107182
- exists:
108-
- mix.exs
183+
- opsm_ex/mix.exs
109184
allow_failure: true
110185
# ==================
111186
# Testing
@@ -114,45 +189,79 @@ cargo-test:
114189
stage: test
115190
image: rust:1.97
116191
script:
117-
- cargo test --all-features
192+
- |
193+
for dir in $RUST_CRATE_DIRS; do
194+
echo "== cargo test: $dir =="
195+
(cd "$dir" && cargo test --all-features)
196+
done
118197
rules:
119198
- exists:
120-
- Cargo.toml
199+
- opsm-ui/tui/Cargo.toml
200+
- opsm_ex/native/opsm_pq_nif/Cargo.toml
201+
- opsm_ex/native/quic_transport/Cargo.toml
202+
- services/checky-monkey/Cargo.toml
203+
- services/oikos/Cargo.toml
204+
- services/palimpsest-license/Cargo.toml
205+
- services/selur/Cargo.toml
206+
- services/svalinn/Cargo.toml
207+
- services/vordr/Cargo.toml
121208
mix-test:
122209
stage: test
123210
image: elixir:1.19.5-otp-28
124211
script:
212+
- cd opsm_ex
125213
- mix local.hex --force
126214
- mix deps.get
127215
- mix test
128216
rules:
129217
- exists:
130-
- mix.exs
218+
- opsm_ex/mix.exs
131219
# ==================
132220
# Build
133221
# ==================
134222
cargo-build:
135223
stage: build
136224
image: rust:1.97
137225
script:
138-
- cargo build --release
226+
- |
227+
for dir in $RUST_CRATE_DIRS; do
228+
echo "== cargo build --release: $dir =="
229+
(cd "$dir" && cargo build --release)
230+
done
139231
artifacts:
140232
paths:
141-
- target/release/
233+
- opsm-ui/tui/target/release/
234+
- opsm_ex/native/opsm_pq_nif/target/release/
235+
- opsm_ex/native/quic_transport/target/release/
236+
- services/checky-monkey/target/release/
237+
- services/oikos/target/release/
238+
- services/palimpsest-license/target/release/
239+
- services/selur/target/release/
240+
- services/svalinn/target/release/
241+
- services/vordr/target/release/
142242
expire_in: 1 week
143243
rules:
144244
- exists:
145-
- Cargo.toml
245+
- opsm-ui/tui/Cargo.toml
246+
- opsm_ex/native/opsm_pq_nif/Cargo.toml
247+
- opsm_ex/native/quic_transport/Cargo.toml
248+
- services/checky-monkey/Cargo.toml
249+
- services/oikos/Cargo.toml
250+
- services/palimpsest-license/Cargo.toml
251+
- services/selur/Cargo.toml
252+
- services/svalinn/Cargo.toml
253+
- services/vordr/Cargo.toml
146254
mix-build:
147255
stage: build
148256
image: elixir:1.19.5-otp-28
149257
script:
258+
- cd opsm_ex
150259
- mix local.hex --force
151260
- mix deps.get
152261
- MIX_ENV=prod mix compile
153262
rules:
154263
- exists:
155-
- mix.exs
264+
- opsm_ex/mix.exs
156265
trufflehog:
157266
stage: security
158267
image: trufflesecurity/trufflehog:latest

0 commit comments

Comments
 (0)