From 0ac821904980b7952dd47a39f23b47c10ba5def8 Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 15 Sep 2026 18:07:43 +0000 Subject: [PATCH] fix: verify npm SHA-1 checksums and drop sh invoke npm shasum used SHA-256, so integrity checks could not match registry metadata. Remove sh from package export invoke allowlist and switch the fiber adapter to argv-style go run. Tighten CI/release checkout perms. Amp-Thread-ID: https://ampcode.com/threads/T-01a0a631-f6de-735d-b395-b45d281f927e Co-authored-by: Max Carter --- .github/workflows/ci.yml | 13 +++++++++++++ .github/workflows/release.yml | 4 ++++ .../adapters/go:fiber/inauguration.adapter.json | 8 ++++---- in-cli/Cargo.lock | 1 + in-cli/Cargo.toml | 1 + in-cli/src/package_install.rs | 16 +++++++++++++++- in-cli/src/package_runtime.rs | 12 +++++++++++- 7 files changed, 49 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b2f435c..21f0149e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,12 +5,17 @@ on: branches: [master, main] pull_request: +permissions: + contents: read + jobs: in-cli: name: in-cli (fmt/clippy/test) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@stable with: components: clippy, rustfmt @@ -29,6 +34,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@stable - name: Build protocol-gen run: cargo build --bin protocol-gen @@ -44,6 +51,8 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@stable - name: Install rust-src run: rustup component add rust-src @@ -64,6 +73,8 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@stable - name: Install rust-src run: rustup component add rust-src @@ -80,6 +91,8 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@stable - name: Install rust-src run: rustup component add rust-src diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 38c0a32b..c054dce3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,6 +19,8 @@ jobs: timeout-minutes: 90 steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@stable - name: Install rust-src (for self-host sysroot) run: rustup component add rust-src @@ -67,6 +69,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} diff --git a/apps/package-ecosystem-sample/adapters/go:fiber/inauguration.adapter.json b/apps/package-ecosystem-sample/adapters/go:fiber/inauguration.adapter.json index 8f75d1fa..2d037cd6 100644 --- a/apps/package-ecosystem-sample/adapters/go:fiber/inauguration.adapter.json +++ b/apps/package-ecosystem-sample/adapters/go:fiber/inauguration.adapter.json @@ -4,12 +4,12 @@ "symbol": "fiber_greet", "returns": "string", "invoke": { - "program": "sh", + "program": "go", "args": [ - "-c", - "cd inauguration-invoke && go run ." + "run", + "./inauguration-invoke" ] } } ] -} \ No newline at end of file +} diff --git a/in-cli/Cargo.lock b/in-cli/Cargo.lock index 66ef3546..f0630288 100644 --- a/in-cli/Cargo.lock +++ b/in-cli/Cargo.lock @@ -543,6 +543,7 @@ dependencies = [ "quote", "serde", "serde_json", + "sha1", "sha2", "syn 2.0.119", "tar", diff --git a/in-cli/Cargo.toml b/in-cli/Cargo.toml index abb9a902..4494d391 100644 --- a/in-cli/Cargo.toml +++ b/in-cli/Cargo.toml @@ -31,6 +31,7 @@ libc = "0.2" quote = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" +sha1 = "0.11" sha2 = "0.11" syn = { version = "2", features = ["full"] } thiserror = "2" diff --git a/in-cli/src/package_install.rs b/in-cli/src/package_install.rs index 7331b6e9..7cdd4f36 100644 --- a/in-cli/src/package_install.rs +++ b/in-cli/src/package_install.rs @@ -761,7 +761,7 @@ fn verify_archive_checksum(path: &Path, checksum: &ArtifactChecksum) -> Result<( match checksum { ArtifactChecksum::Sha1Hex(expected) => verify_hex_digest( expected, - &hex_encode(&sha2::Sha256::digest(&data)), + &hex_encode(&sha1::Sha1::digest(&data)), path, "sha1", ), @@ -1045,6 +1045,7 @@ fn curl_to_file(url: &str, path: &Path) -> Result<(), String> { })?; } let status = Command::new("curl") + .env_clear() .args([ "-fsSL", "-A", @@ -1079,6 +1080,13 @@ pub fn lock_dependencies(path: &Path) -> Result<(PathBuf, PackageLock), String> mod tests { use super::*; + #[test] + fn require_https_rejects_non_https() { + assert!(require_https("https://example.com/pkg").is_ok()); + assert!(require_https("http://example.com/pkg").is_err()); + assert!(require_https("file:///tmp/pkg").is_err()); + } + #[test] fn verify_archive_checksum_error_paths() { let dir = tempfile_dir("verify-checksum-err"); @@ -1087,6 +1095,12 @@ mod tests { let sha1 = ArtifactChecksum::Sha1Hex("badsha1".to_string()); assert!(verify_archive_checksum(&path, &sha1).is_err()); + let sha1_ok = + ArtifactChecksum::Sha1Hex("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed".to_string()); + assert!( + verify_archive_checksum(&path, &sha1_ok).is_ok(), + "npm shasum is SHA-1 of the archive bytes, not SHA-256" + ); let sha256 = ArtifactChecksum::Sha256Hex("badsha256".to_string()); assert!(verify_archive_checksum(&path, &sha256).is_err()); diff --git a/in-cli/src/package_runtime.rs b/in-cli/src/package_runtime.rs index 1d6bff6e..9e2bc1f4 100644 --- a/in-cli/src/package_runtime.rs +++ b/in-cli/src/package_runtime.rs @@ -85,7 +85,7 @@ pub fn invoke_package_export( } } -const ALLOWED_INVOKE_PROGRAMS: &[&str] = &["echo", "node", "python3", "cargo", "go", "sh", "true"]; +const ALLOWED_INVOKE_PROGRAMS: &[&str] = &["echo", "node", "python3", "cargo", "go", "true"]; pub fn run_invoke(spec: &PackageInvokeSpec, install_path: &Path) -> Result { if !ALLOWED_INVOKE_PROGRAMS.contains(&spec.program.as_str()) { @@ -176,6 +176,16 @@ mod tests { assert_eq!(value, Value::String("ok".to_string())); } + #[test] + fn rejects_shell_invoke_program() { + let spec = PackageInvokeSpec { + program: "sh".to_string(), + args: vec!["-c".to_string(), "echo pwned".to_string()], + }; + let err = run_invoke(&spec, Path::new(".")).expect_err("sh must not be allowlisted"); + assert!(err.contains("not in the allowlist")); + } + #[test] fn test_binding_return_type_mapping() { let cases = vec![