Skip to content

Commit 7cb049b

Browse files
ci(rust): convert rust-ci.yml to thin wrapper (standards#174) (#18)
* ci(rust): convert rust-ci.yml to thin wrapper (standards#174) Replaces the per-repo `rust-ci.yml` copy with a 5-line wrapper invoking the shared reusable workflow in `hyperpolymath/standards` (PR #174). Pinned to PR #174's HEAD SHA `4fdf4314b4ab54269adbaff10e30e483b5e86845`; will resolve to standards/main once #174 merges. Estate audit found ~87 rust-ci.yml copies across the estate; this is one of them. The reusable provides identical cargo check/clippy/fmt/test behaviour with opt-in `enable_audit` + `enable_coverage` inputs. Pattern precedent: standards#168 (governance-reusable) + downstream wrappers absolute-zero#41 + tma-mark2#41. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(sweep): codeql actions matrix, safedom .res→.affine - Replace codeql.yml `javascript-typescript` matrix entry with `actions` (repo has no JS/TS source). Matches the canonical fix in rsr-template-repo#71 / mtpc#8 / thunderbird#75. - Replace examples/SafeDOMExample.res with the canonical examples/SafeDOMExample.affine (per gitbot-fleet#208 and the banned-ReScript anti-pattern policy). --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 760e63b commit 7cb049b

4 files changed

Lines changed: 139 additions & 212 deletions

File tree

.github/workflows/codeql.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ jobs:
3030
fail-fast: false
3131
matrix:
3232
include:
33-
- language: javascript-typescript
33+
# Repo source is not JS/TS; scan workflow files via the
34+
# actions extractor (every repo has those). See hypatia rule
35+
# codeql_language_matrix_mismatch.
36+
- language: actions
3437
build-mode: none
3538

3639
steps:

.github/workflows/rust-ci.yml

Lines changed: 6 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,17 @@
11
# SPDX-License-Identifier: MPL-2.0
2-
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3-
#
4-
# rust-ci.yml — Cargo build, test, clippy, and fmt for Rust projects.
5-
# Only runs if Cargo.toml exists in the repo root.
2+
# Rust CI — thin wrapper calling the shared estate reusable in
3+
# hyperpolymath/standards. Configure once, propagate everywhere.
4+
# See: docs/CI-REUSABLE-WORKFLOWS.adoc in standards.
65
name: Rust CI
76

87
on:
9-
pull_request:
10-
branches: ['**']
118
push:
129
branches: [main, master]
10+
pull_request:
1311

1412
permissions:
1513
contents: read
1614

1715
jobs:
18-
check:
19-
name: Cargo check + clippy + fmt
20-
runs-on: ubuntu-latest
21-
22-
steps:
23-
- name: Checkout repository
24-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25-
26-
# robofishy's build.rs invokes `alr build` on the SPARK safety
27-
# kernel, so CI runners need Alire + a GNAT toolchain before
28-
# cargo can link the crate. We install Alire 2.1.0 directly from
29-
# the upstream release binary rather than going through the
30-
# alire-project/setup-alire action — the action's v1 tag pins an
31-
# older Alire that does not regenerate config/safety_kernel_config.gpr
32-
# on `alr build`, which breaks gprbuild with "unknown variable
33-
# Build_Profile" before any Rust code is touched.
34-
- name: Install Alire 2.1.0
35-
run: |
36-
set -euo pipefail
37-
ALIRE_VERSION="2.1.0"
38-
ALIRE_URL="https://github.com/alire-project/alire/releases/download/v${ALIRE_VERSION}/alr-${ALIRE_VERSION}-bin-x86_64-linux.zip"
39-
ALIRE_SHA256="e3b32cb0afe981b23d1a68da77452cf81ee1d82de8ebaf01c5e233be8b463fbe"
40-
curl -fsSL "$ALIRE_URL" -o /tmp/alr.zip
41-
echo "$ALIRE_SHA256 /tmp/alr.zip" | sha256sum -c -
42-
mkdir -p "$HOME/.alire"
43-
unzip -q /tmp/alr.zip -d "$HOME/.alire"
44-
echo "$HOME/.alire/bin" >> "$GITHUB_PATH"
45-
- name: Select GNAT toolchain via Alire
46-
run: |
47-
alr -n toolchain --disable-assistant --select gnat_native gprbuild
48-
49-
- name: Install Rust toolchain
50-
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
51-
with:
52-
components: clippy, rustfmt
53-
54-
- name: Cache cargo registry and build
55-
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
56-
57-
- name: Cargo check
58-
run: cargo check --all-targets 2>&1
59-
60-
- name: Cargo fmt
61-
run: cargo fmt --all -- --check
62-
63-
- name: Cargo clippy
64-
run: cargo clippy --all-targets -- -D warnings
65-
66-
test:
67-
name: Cargo test
68-
runs-on: ubuntu-latest
69-
needs: check
70-
71-
steps:
72-
- name: Checkout repository
73-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
74-
75-
# robofishy's build.rs invokes `alr build` on the SPARK safety
76-
# kernel, so CI runners need Alire + a GNAT toolchain before
77-
# cargo can link the crate. We install Alire 2.1.0 directly from
78-
# the upstream release binary rather than going through the
79-
# alire-project/setup-alire action — the action's v1 tag pins an
80-
# older Alire that does not regenerate config/safety_kernel_config.gpr
81-
# on `alr build`, which breaks gprbuild with "unknown variable
82-
# Build_Profile" before any Rust code is touched.
83-
- name: Install Alire 2.1.0
84-
run: |
85-
set -euo pipefail
86-
ALIRE_VERSION="2.1.0"
87-
ALIRE_URL="https://github.com/alire-project/alire/releases/download/v${ALIRE_VERSION}/alr-${ALIRE_VERSION}-bin-x86_64-linux.zip"
88-
ALIRE_SHA256="e3b32cb0afe981b23d1a68da77452cf81ee1d82de8ebaf01c5e233be8b463fbe"
89-
curl -fsSL "$ALIRE_URL" -o /tmp/alr.zip
90-
echo "$ALIRE_SHA256 /tmp/alr.zip" | sha256sum -c -
91-
mkdir -p "$HOME/.alire"
92-
unzip -q /tmp/alr.zip -d "$HOME/.alire"
93-
echo "$HOME/.alire/bin" >> "$GITHUB_PATH"
94-
- name: Select GNAT toolchain via Alire
95-
run: |
96-
alr -n toolchain --disable-assistant --select gnat_native gprbuild
97-
98-
- name: Install Rust toolchain
99-
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
100-
101-
- name: Cache cargo registry and build
102-
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
103-
104-
- name: Run tests
105-
run: cargo test --all-targets
106-
107-
- name: Write summary
108-
if: always()
109-
run: |
110-
echo "## Rust CI Results" >> "$GITHUB_STEP_SUMMARY"
111-
echo "" >> "$GITHUB_STEP_SUMMARY"
112-
echo "- **cargo check**: passed" >> "$GITHUB_STEP_SUMMARY"
113-
echo "- **cargo test**: completed" >> "$GITHUB_STEP_SUMMARY"
16+
rust-ci:
17+
uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@4fdf4314b4ab54269adbaff10e30e483b5e86845

examples/SafeDOMExample.affine

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
// SafeDOMExample.affine — formally-verified DOM mounting (aspirational).
3+
//
4+
// This example shows the *shape* of SafeDOM consumer code in current
5+
// AffineScript syntax. The `SafeDOM` stdlib surface it references
6+
// (`mount_safe`, `mount_when_ready`, `mount_batch`,
7+
// `proven_selector_validate`, `proven_html_validate`, `mount`) is the
8+
// target of `affinescript#56` (DOM+Pixi binding survey) and does not
9+
// yet exist in the published stdlib. The file is therefore
10+
// parse-checked but not type-checked end-to-end until #56 lands the
11+
// bindings; `affinescript check` reports `Resolve.UndefinedModule
12+
// SafeDOM` which is expected.
13+
//
14+
// Previous versions of this file (estate-wide, 5 dialect variants)
15+
// pre-dated ADR-014 (qualified paths), ADR-016 (effect rows), and the
16+
// `#{`-record-literal sigil (ADR-215). They were retired in favour of
17+
// this canonical via the gitbot-fleet#208 sweep (2026-05-26).
18+
19+
module SafeDOMExample;
20+
21+
use prelude::{Option, Some, None, Result, Ok, Err};
22+
23+
// `Element` and friends are nominal extern types for now — the real
24+
// shape lands with affinescript#56.
25+
extern type Element;
26+
extern type Selector;
27+
extern type ValidHTML;
28+
29+
// Single-mount status, lifted from the host into a typed tag union.
30+
enum MountStatus {
31+
Mounted(Element),
32+
MountPointNotFound(String),
33+
InvalidSelector(String),
34+
InvalidHTML(String)
35+
}
36+
37+
// Batch-mount result.
38+
enum MountResult {
39+
Mounted([Element]),
40+
Failed(String)
41+
}
42+
43+
// Spec for one element in a batch mount.
44+
struct MountSpec {
45+
selector: String,
46+
html: String
47+
}
48+
49+
// SafeDOM's host-side surface, all IO-effecting. Callbacks are passed
50+
// as separate parameters (rather than a `MountCallbacks` record)
51+
// because fn-typed struct fields are not currently parser-supported.
52+
extern fn mount_safe(
53+
selector: ref String,
54+
html: ref String,
55+
on_success: fn(Element) -> (),
56+
on_error: fn(String) -> (),
57+
) -{IO}-> ();
58+
59+
extern fn mount_when_ready(
60+
selector: ref String,
61+
html: ref String,
62+
on_success: fn(Element) -> (),
63+
on_error: fn(String) -> (),
64+
) -{IO}-> ();
65+
66+
extern fn mount_batch(specs: ref [MountSpec]) -{IO}-> MountResult;
67+
68+
extern fn proven_selector_validate(s: ref String) -{IO}-> Result<Selector, String>;
69+
extern fn proven_html_validate(s: ref String) -{IO}-> Result<ValidHTML, String>;
70+
extern fn mount(sel: ref Selector, html: ref ValidHTML) -{IO}-> MountStatus;
71+
72+
extern fn array_for_each(xs: ref [Element], f: fn(Element) -> ()) -{IO}-> ();
73+
extern fn array_len(xs: ref [Element]) -> Int;
74+
75+
// Example 1 — basic mount with success/error branches.
76+
pub fn mount_app() -{IO}-> () {
77+
mount_safe(
78+
"#app",
79+
"<div><h1>Hello, World!</h1><p>Mounted safely with proofs.</p></div>",
80+
fn(el) -> () { Console::log("App mounted successfully"); },
81+
fn(err) -> () { Console::error("Mount failed: " ++ err); },
82+
);
83+
}
84+
85+
// Example 2 — defer until DOM ready.
86+
pub fn mount_when_dom_ready() -{IO}-> () {
87+
mount_when_ready(
88+
"#app",
89+
"<div class='container'><h1>App Title</h1></div>",
90+
fn(_el) -> () { Console::log("Mounted after DOM ready"); },
91+
fn(err) -> () { Console::error("Failed: " ++ err); },
92+
);
93+
}
94+
95+
// Example 3 — atomic batch mount.
96+
pub fn mount_multiple() -{IO}-> () {
97+
let specs = [
98+
MountSpec #{ selector: "#header", html: "<header><h1>Site Title</h1></header>" },
99+
MountSpec #{ selector: "#nav", html: "<nav><a href='/'>Home</a></nav>" },
100+
MountSpec #{ selector: "#main", html: "<main><p>Content here</p></main>" },
101+
MountSpec #{ selector: "#footer", html: "<footer>2026</footer>" },
102+
];
103+
104+
match mount_batch(specs) {
105+
Mounted(elements) => {
106+
Console::log("Batch mount succeeded");
107+
array_for_each(elements, fn(_el) -> () { Console::log(" element"); });
108+
},
109+
Failed(err) => {
110+
Console::error("Batch mount failed (atomic — none mounted): " ++ err);
111+
}
112+
}
113+
}
114+
115+
// Example 4 — explicit two-stage validation before mounting.
116+
pub fn mount_with_validation() -{IO}-> () {
117+
match proven_selector_validate("#my-app") {
118+
Err(e) => Console::error("Invalid selector: " ++ e),
119+
Ok(valid_selector) => match proven_html_validate("<div>Content</div>") {
120+
Err(e) => Console::error("Invalid HTML: " ++ e),
121+
Ok(valid_html) => match mount(valid_selector, valid_html) {
122+
Mounted(_el) => Console::log("Mounted with validated inputs"),
123+
MountPointNotFound(s) => Console::error("Element not found: " ++ s),
124+
InvalidSelector(_) => Console::error("impossible — already validated"),
125+
InvalidHTML(_) => Console::error("impossible — already validated"),
126+
},
127+
},
128+
}
129+
}

examples/SafeDOMExample.res

Lines changed: 0 additions & 109 deletions
This file was deleted.

0 commit comments

Comments
 (0)