First working iteration: check -> fetch -> verify for a real package
Rust PoC (cargo, packages.d/*.toml config) that checks astral-sh/uv's
GitHub Atom feed for a new release, fetches the matching asset via the
GitHub API, and verifies it. Confirmed live against the real repo: uv
actually ships GitHub build-provenance attestations (sigstore bundle) on
every release, so it's a tier-2 package, not the tier-4 same-origin-sha256
guessed in the original spec draft. Verified via `gh attestation verify`
rather than reimplementing sigstore in Rust. State persists across runs so
a second run correctly reports "up to date."
Also folds the finding back into SPEC.md: updates the uv example to
tier 2, derives tier from verification method instead of storing both
(avoids a tier/method mismatch that would mean nothing), marks the
packages.d/ layout question resolved, and updates Architecture/Status to
say what's actually implemented vs. still sketch (build/publish/review
queue, same-origin-sha256 against a live repo, scheduling, non-GitHub
sources, minisign are all still open).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2FEut5tVMNjeVjqhgVZbr
2026-09-11 08:04:48 +00:00
|
|
|
mod checker;
|
|
|
|
|
mod config;
|
|
|
|
|
mod fetcher;
|
|
|
|
|
mod state;
|
|
|
|
|
mod verifier;
|
|
|
|
|
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
|
|
/// First iteration: check -> fetch -> verify -> report, for whatever is
|
|
|
|
|
/// in packages.d/. No build/publish step yet (see SPEC.md > Status).
|
|
|
|
|
fn main() -> Result<()> {
|
|
|
|
|
let client = reqwest::blocking::Client::builder()
|
|
|
|
|
.user_agent("pkgwatch/0.1 (PoC; https://code.austinschaefer.com)")
|
|
|
|
|
.build()?;
|
|
|
|
|
|
|
|
|
|
let packages_dir = Path::new("packages.d");
|
|
|
|
|
let state_dir = Path::new("state");
|
|
|
|
|
let work_dir = Path::new("work");
|
|
|
|
|
|
|
|
|
|
let packages = config::load_packages_dir(packages_dir)?;
|
|
|
|
|
if packages.is_empty() {
|
|
|
|
|
println!("no packages configured under {}/", packages_dir.display());
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (name, pkg) in packages {
|
|
|
|
|
println!("== {name} ({}) ==", pkg.repo);
|
|
|
|
|
|
|
|
|
|
let latest = checker::latest_github_release(&client, &pkg.repo)?;
|
|
|
|
|
let last_seen = state::load_last_version(state_dir, &name);
|
|
|
|
|
|
|
|
|
|
if last_seen.as_deref() == Some(latest.as_str()) {
|
|
|
|
|
println!(" up to date at {latest}");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println!(" new version detected: {latest} (previously: {last_seen:?})");
|
|
|
|
|
|
|
|
|
|
let dest_dir = work_dir.join(&name).join(&latest);
|
2026-09-17 07:00:53 +00:00
|
|
|
let asset_name = pkg
|
|
|
|
|
.asset_pattern
|
|
|
|
|
.replace("{version}", checker::version_from_tag(&latest));
|
First working iteration: check -> fetch -> verify for a real package
Rust PoC (cargo, packages.d/*.toml config) that checks astral-sh/uv's
GitHub Atom feed for a new release, fetches the matching asset via the
GitHub API, and verifies it. Confirmed live against the real repo: uv
actually ships GitHub build-provenance attestations (sigstore bundle) on
every release, so it's a tier-2 package, not the tier-4 same-origin-sha256
guessed in the original spec draft. Verified via `gh attestation verify`
rather than reimplementing sigstore in Rust. State persists across runs so
a second run correctly reports "up to date."
Also folds the finding back into SPEC.md: updates the uv example to
tier 2, derives tier from verification method instead of storing both
(avoids a tier/method mismatch that would mean nothing), marks the
packages.d/ layout question resolved, and updates Architecture/Status to
say what's actually implemented vs. still sketch (build/publish/review
queue, same-origin-sha256 against a live repo, scheduling, non-GitHub
sources, minisign are all still open).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2FEut5tVMNjeVjqhgVZbr
2026-09-11 08:04:48 +00:00
|
|
|
let artifact_path =
|
2026-09-17 07:00:53 +00:00
|
|
|
fetcher::download_asset(&client, &pkg.repo, &latest, &asset_name, &dest_dir)?;
|
First working iteration: check -> fetch -> verify for a real package
Rust PoC (cargo, packages.d/*.toml config) that checks astral-sh/uv's
GitHub Atom feed for a new release, fetches the matching asset via the
GitHub API, and verifies it. Confirmed live against the real repo: uv
actually ships GitHub build-provenance attestations (sigstore bundle) on
every release, so it's a tier-2 package, not the tier-4 same-origin-sha256
guessed in the original spec draft. Verified via `gh attestation verify`
rather than reimplementing sigstore in Rust. State persists across runs so
a second run correctly reports "up to date."
Also folds the finding back into SPEC.md: updates the uv example to
tier 2, derives tier from verification method instead of storing both
(avoids a tier/method mismatch that would mean nothing), marks the
packages.d/ layout question resolved, and updates Architecture/Status to
say what's actually implemented vs. still sketch (build/publish/review
queue, same-origin-sha256 against a live repo, scheduling, non-GitHub
sources, minisign are all still open).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2FEut5tVMNjeVjqhgVZbr
2026-09-11 08:04:48 +00:00
|
|
|
println!(" fetched {}", artifact_path.display());
|
|
|
|
|
|
|
|
|
|
let result = verifier::verify(
|
|
|
|
|
&client,
|
|
|
|
|
&pkg.verification,
|
|
|
|
|
&pkg.repo,
|
|
|
|
|
&latest,
|
|
|
|
|
&artifact_path,
|
|
|
|
|
&dest_dir,
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
println!(
|
|
|
|
|
" verification (tier {}): {} — {}",
|
|
|
|
|
result.tier,
|
|
|
|
|
if result.passed { "PASS" } else { "FAIL" },
|
|
|
|
|
result.justification
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
match (result.tier, result.passed) {
|
|
|
|
|
(1..=3, true) => {
|
|
|
|
|
println!(" tier 1-3 pass: would auto-build + publish (not yet implemented)");
|
|
|
|
|
state::save_last_version(state_dir, &name, &latest)?;
|
|
|
|
|
}
|
|
|
|
|
(_, true) => {
|
|
|
|
|
println!(" tier 4-6 pass: flagging for human review, not auto-publishing");
|
Set up project tooling to match the rest of ~/dev's Rust fleet
Surveyed sporah/doubleo7/feedsignal/uy-immigration-watcher/notif-picker
for conventions and replicated the current dominant pattern rather than
inventing a new one:
- Forgejo CI (.forgejo/workflows/ci.yml): build/test/audit jobs on the
rust-ci runner label, cargo+sccache caching, cargo fmt --check, cargo
clippy --all-targets -- -D warnings, cargo audit. Matches
sporah/doubleo7/feedsignal/uy-immigration-watcher; notif-picker's
docker-label/manual-toolchain-install variant looks like an earlier
iteration superseded by this one.
- Makefile.toml with format/format-check/lint/test/audit/build tasks and
a `ci` task chaining them — copied from notif-picker's clean version,
the only project that had this pattern. `cargo make ci` now runs the
same checks locally that CI runs.
- Explicit empty [workspace] in Cargo.toml (doubleo7's pattern) so a
nested git-worktree checkout can't accidentally inherit an ancestor
directory's workspace manifest.
- rustfmt: no rustfmt.toml, matching every sibling project — default
style is the established convention here, not an oversight.
New for this fleet, since nothing else in ~/dev has it: a git-native
pre-commit hook (.githooks/pre-commit, activated via `cargo make
install-hooks` / `git config core.hooksPath .githooks`) that runs `cargo
fmt` and re-stages whatever it reformats. Chose git's native hooksPath
over the pre-commit(.com) framework or cargo-husky — no extra runtime
dependency, hook is tracked and shareable, and nothing else here needs
Python. Kept to formatting only; clippy/audit stay in CI, which already
covers them and can run heavier checks than a commit hook should.
Fixed one clippy finding (useless format! in checker.rs) and reformatted
the existing code to match the now-enforced default rustfmt style.
`cargo make ci` passes clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2FEut5tVMNjeVjqhgVZbr
2026-09-11 08:13:29 +00:00
|
|
|
println!(
|
|
|
|
|
" (review-queue persistence not yet implemented — this is where it plugs in)"
|
|
|
|
|
);
|
First working iteration: check -> fetch -> verify for a real package
Rust PoC (cargo, packages.d/*.toml config) that checks astral-sh/uv's
GitHub Atom feed for a new release, fetches the matching asset via the
GitHub API, and verifies it. Confirmed live against the real repo: uv
actually ships GitHub build-provenance attestations (sigstore bundle) on
every release, so it's a tier-2 package, not the tier-4 same-origin-sha256
guessed in the original spec draft. Verified via `gh attestation verify`
rather than reimplementing sigstore in Rust. State persists across runs so
a second run correctly reports "up to date."
Also folds the finding back into SPEC.md: updates the uv example to
tier 2, derives tier from verification method instead of storing both
(avoids a tier/method mismatch that would mean nothing), marks the
packages.d/ layout question resolved, and updates Architecture/Status to
say what's actually implemented vs. still sketch (build/publish/review
queue, same-origin-sha256 against a live repo, scheduling, non-GitHub
sources, minisign are all still open).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2FEut5tVMNjeVjqhgVZbr
2026-09-11 08:04:48 +00:00
|
|
|
}
|
|
|
|
|
(_, false) => {
|
|
|
|
|
println!(" verification failed — not publishing, not updating state");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|