Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ jobs:
- name: Setup Erlang/Elixir
uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
with:
otp-version: '27.0'
elixir-version: '1.17'
# Versions derive from opsm.toml [runtime] via .tool-versions
# (generated by `just toolchain-sync` — see docs/TOOLCHAIN.adoc)
version-file: '.tool-versions'
version-type: 'strict'
- name: Restore Mix cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v4
with:
Expand All @@ -65,8 +67,10 @@ jobs:
- name: Setup Erlang/Elixir
uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
with:
otp-version: '27.0'
elixir-version: '1.17'
# Versions derive from opsm.toml [runtime] via .tool-versions
# (generated by `just toolchain-sync` — see docs/TOOLCHAIN.adoc)
version-file: '.tool-versions'
version-type: 'strict'
- name: Restore Mix cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v4
with:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/echidna-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ jobs:
if: steps.detect.outputs.relevant == 'true'
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
with:
# Pinned to the canonical rust version in opsm.toml [runtime]
toolchain: '1.97.0'
components: clippy
- name: Cache Rust dependencies
if: steps.detect.outputs.relevant == 'true'
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/nif-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,20 @@ jobs:
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
with:
# Pinned to the canonical rust version in opsm.toml [runtime]
toolchain: '1.97.0'
- name: Cache Rust build
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
with:
workspaces: opsm_ex/native/opsm_pq_nif -> target
- name: Setup Erlang/Elixir
uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
with:
otp-version: "27.0"
elixir-version: "1.17"
# Versions derive from opsm.toml [runtime] via .tool-versions
# (generated by `just toolchain-sync` — see docs/TOOLCHAIN.adoc)
version-file: '.tool-versions'
version-type: 'strict'
- name: Restore Mix cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v4
with:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/trust-pipeline-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ jobs:
- name: Install Elixir and OTP
uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
with:
otp-version: '26.2'
elixir-version: '1.16.0'
# Versions derive from opsm.toml [runtime] via .tool-versions
# (generated by `just toolchain-sync` — see docs/TOOLCHAIN.adoc)
version-file: '.tool-versions'
version-type: 'strict'
- name: Cache Mix dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v4
with:
Expand Down
29 changes: 17 additions & 12 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# SPDX-License-Identifier: MPL-2.0
// Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
# Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
# Primary CI/CD - GitLab is the source of truth
#
# Toolchain images (elixir/rust) are pinned to the canonical versions in
# opsm.toml [runtime] — drift is gated by `just toolchain-check`.
# Scanner images (trivy/semgrep/trufflehog) deliberately float: their
# detection databases need to stay fresh, so pinning them is worse.

stages:
- security
Expand Down Expand Up @@ -32,7 +37,7 @@ semgrep:
allow_failure: true
cargo-audit:
stage: security
image: rust:latest
image: rust:1.97
script:
- cargo install cargo-audit
- cargo audit
Expand All @@ -41,7 +46,7 @@ cargo-audit:
- Cargo.toml
cargo-deny:
stage: security
image: rust:latest
image: rust:1.97
script:
- cargo install cargo-deny
- cargo deny check
Expand All @@ -51,7 +56,7 @@ cargo-deny:
allow_failure: true
mix-audit:
stage: security
image: elixir:latest
image: elixir:1.19.5-otp-28
script:
- mix local.hex --force
- mix archive.install hex mix_audit --force
Expand All @@ -66,7 +71,7 @@ mix-audit:
# ==================
rustfmt:
stage: lint
image: rust:latest
image: rust:1.97
script:
- rustup component add rustfmt
- cargo fmt -- --check
Expand All @@ -75,7 +80,7 @@ rustfmt:
- Cargo.toml
clippy:
stage: lint
image: rust:latest
image: rust:1.97
script:
- rustup component add clippy
- cargo clippy -- -D warnings
Expand All @@ -85,15 +90,15 @@ clippy:
allow_failure: true
mix-format:
stage: lint
image: elixir:latest
image: elixir:1.19.5-otp-28
script:
- mix format --check-formatted
rules:
- exists:
- mix.exs
credo:
stage: lint
image: elixir:latest
image: elixir:1.19.5-otp-28
script:
- mix local.hex --force
- mix deps.get
Expand All @@ -107,15 +112,15 @@ credo:
# ==================
cargo-test:
stage: test
image: rust:latest
image: rust:1.97
script:
- cargo test --all-features
rules:
- exists:
- Cargo.toml
mix-test:
stage: test
image: elixir:latest
image: elixir:1.19.5-otp-28
script:
- mix local.hex --force
- mix deps.get
Expand All @@ -128,7 +133,7 @@ mix-test:
# ==================
cargo-build:
stage: build
image: rust:latest
image: rust:1.97
script:
- cargo build --release
artifacts:
Expand All @@ -140,7 +145,7 @@ cargo-build:
- Cargo.toml
mix-build:
stage: build
image: elixir:latest
image: elixir:1.19.5-otp-28
script:
- mix local.hex --force
- mix deps.get
Expand Down
18 changes: 16 additions & 2 deletions .machine_readable/6a2/STATE.a2ml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# SPDX-License-Identifier: MPL-2.0
# STATE.a2ml — Project state checkpoint
# Updated 2026-04-25f: CRG-B achieved — 6 external targets documented
# Updated 2026-07-09: toolchain single source of truth (opsm.toml [runtime])

[metadata]
project = "odds-and-sods-package-manager"
version = "2.0.0"
last-updated = "2026-04-25"
last-updated = "2026-07-09"
status = "first-class system active"

[project-context]
Expand Down Expand Up @@ -169,5 +169,19 @@ evidence-file = "READINESS.md"
- Health poll loop (180s deadline, 3s interval) before running tests
- Full diagnostics (service logs) on failure; docker compose down always

[completed-2026-07-09]
- Toolchain single source of truth established: opsm.toml [runtime] canonical ✅
- Stale pins corrected (erlang 26.2.0→28.3.1, elixir 1.16.0→1.19.5-otp-28)
- Pin set completed: rust 1.97.0, nickel 1.16.0 (was unpinned), idris2 0.8.0
- Vestigial nodejs pin dropped — Deno is the sole JS runtime
- .tool-versions now GENERATED (scripts/toolchain.sh; just toolchain-sync)
- Drift gate: just toolchain-check, wired into Mustfile
- GitLab CI images pinned off :latest; GitHub workflows read .tool-versions
via setup-beam version-file (previously 3 disagreeing hardcoded sets)
- [runtime] parser hardened: comment lines + inline comments (manager.ex)
- Full story: docs/TOOLCHAIN.adoc (incl. bootstrap layering + Idris2/pack route)

[next-actions]
- Grade A: requires external user confirmation outside hyperpolymath
- guix.scm is a stub (source #f) — grow into real manifest (erlang, elixir,
zig, just, nickel, idris2, chez-scheme, gmp) for reproducible bootstrap
21 changes: 15 additions & 6 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
# SPDX-License-Identifier: MPL-2.0
# Pinned runtime versions for OPSM
# Managed via asdf (https://asdf-vm.com)
elixir 1.19.5-otp-28
# GENERATED FILE — do not edit by hand.
# Source of truth: opsm.toml [runtime]. Regenerate with: just toolchain-sync
# Drift is CI-gated by: just toolchain-check
#
# Plugin sources: erlang/elixir via the standard asdf plugins;
# zig, deno, nickel via https://github.com/hyperpolymath/asdf-tool-plugins
#
# Canonical pins deliberately NOT listed here (see docs/TOOLCHAIN.adoc):
# idris2 0.8.0 — no asdf plugin; provision via pack + Chez Scheme + GMP
# rust 1.97.0 — asdf-global-managed to avoid cargo-audit conflicts; CI pins it
erlang 28.3.1
# Note: Rust managed via asdf global (nightly). Not pinned here to avoid
# conflicting with cargo-audit and other cargo subcommands.
nodejs 25.6.1
elixir 1.19.5-otp-28
zig 0.14.0
just 1.46.0
deno 2.6.10
nickel 1.16.0
12 changes: 12 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ fmt-check:
# Format all code
fmt: fmt-ex fmt-deno

# ═══════════════════════════════════════════════════════════════════════════════
# TOOLCHAIN (single source of truth: opsm.toml [runtime] — docs/TOOLCHAIN.adoc)
# ═══════════════════════════════════════════════════════════════════════════════

# Regenerate .tool-versions from opsm.toml [runtime]
toolchain-sync:
sh scripts/toolchain.sh sync

# Verify .tool-versions and CI image pins match opsm.toml [runtime]
toolchain-check:
sh scripts/toolchain.sh check

# ═══════════════════════════════════════════════════════════════════════════════
# RUN
# ═══════════════════════════════════════════════════════════════════════════════
Expand Down
2 changes: 2 additions & 0 deletions Mustfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ checks:
run: just test
- name: format
run: just fmt
- name: toolchain
run: just toolchain-check

Loading
Loading