Skip to content

fix(install): make checksum verification mandatory#1

Open
areporeporepo wants to merge 3 commits intomainfrom
fix/install-mandatory-checksum
Open

fix(install): make checksum verification mandatory#1
areporeporepo wants to merge 3 commits intomainfrom
fix/install-mandatory-checksum

Conversation

@areporeporepo
Copy link
Copy Markdown
Owner

@areporeporepo areporeporepo commented Mar 26, 2026

Summary

  • verify_checksum() now errors instead of warning when sha256sum/shasum is unavailable or when no checksum entry exists for the archive
  • main() now errors when the checksums file cannot be downloaded
  • Add --no-verify-checksum flag and OPENSHELL_NO_VERIFY env var for explicit opt-out
  • Update usage() with new flag, env var, and example

Related Issue

Closes NVIDIA#590

Testing

  • shellcheck install.sh — passes (zero warnings)
  • sh -n install.sh — syntax valid
  • Existing e2e tests (e2e/install/{sh,bash,zsh}_test.sh) unaffected — they use real releases with checksums

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • No secrets or credentials committed
  • Changes scoped to the issue at hand

Summary by CodeRabbit

  • New Features

    • Added ability to skip checksum verification during installation via environment variable or CLI flag.
    • Enhanced checksum verification to treat failures as fatal errors.
  • Tests

    • Added test coverage for the checksum skip functionality.

Copilot AI review requested due to automatic review settings March 26, 2026 13:52
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

Walkthrough

The installer script now enforces mandatory checksum verification, failing immediately when checksums cannot be downloaded or verification tools are unavailable. An explicit opt-out mechanism via OPENSHELL_NO_VERIFY environment variable and --no-verify-checksum CLI flag is provided. A corresponding e2e test validates skip behavior.

Changes

Cohort / File(s) Summary
Checksum Verification Enforcement
install.sh
Added --no-verify-checksum flag and OPENSHELL_NO_VERIFY environment variable support for explicit skip. Made checksum file download mandatory when verifying; script terminates if download fails or hash tools (shasum/sha256sum) unavailable. Optimized checksum parsing with single awk lookup instead of grep|awk pipeline.
E2E Test Coverage
e2e/install/sh_test.sh
Added test_skip_checksum_env() to validate checksum skip behavior. Verifies binary installation succeeds and skip confirmation message appears when OPENSHELL_NO_VERIFY=1 is set.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 With checksums enforced, our binaries stand tall,
No silent skips when tools aren't installed—we heed the call!
A flag to skip when needed, but default: secure and tight,
Our little warren's defended, wrapped in cryptographic might! 🔐✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(install): make checksum verification mandatory' directly and clearly summarizes the main change: enforcing mandatory checksum verification in the install script.
Linked Issues check ✅ Passed The PR fully addresses the requirements in issue #590: makes checksum verification mandatory, fails when sha256sum is unavailable, errors if checksums file cannot be downloaded, and adds opt-out mechanisms (--no-verify-checksum flag and OPENSHELL_NO_VERIFY env var).
Out of Scope Changes check ✅ Passed All changes in install.sh and the new e2e test are directly related to implementing mandatory checksum verification and its opt-out mechanisms as required by issue #590.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/install-mandatory-checksum

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the security and robustness of the install.sh script by making checksum verification a mandatory step, with clear error handling for missing checksums or tools, and providing an explicit opt-out mechanism. Additionally, it improves compatibility with diverse OpenAI API backends by implementing a fallback strategy for token parameter names and refines the Landlock sandbox logging for better operational visibility.

Highlights

  • Checksum Verification Enforcement: The install.sh script now makes checksum verification mandatory. It will error if no checksum is found for an archive or if the necessary sha256sum/shasum tools are unavailable, instead of merely warning.
  • Checksum Download Robustness: The installation process will now error if it fails to download the checksums file, ensuring that verification cannot be bypassed due to network issues without explicit opt-out.
  • Explicit Checksum Opt-Out: A new --no-verify-checksum flag and OPENSHELL_NO_VERIFY environment variable have been introduced, allowing users to explicitly bypass checksum verification when necessary, though this is not recommended.
  • OpenAI API Compatibility: The backend validation probe for OpenAI chat completions now includes fallback logic to handle both max_completion_tokens (for newer models like GPT-5+) and max_tokens (for legacy/self-hosted backends) when an initial request fails with an HTTP 400.
  • Improved Landlock Sandbox Logging: Logging for the Landlock filesystem sandbox has been enhanced to provide more informative messages, including a warn level message when the sandbox is unavailable, guiding users to set landlock.compatibility to 'hard_requirement' for stricter enforcement.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fallback mechanism for OpenAI chat completion backend validation, allowing the system to first attempt validation with max_completion_tokens and then retry with max_tokens if the initial request fails with a 400 error. This is achieved by adding a fallback_body to the ValidationProbe struct and refactoring the verify_backend_endpoint function, along with new unit tests to cover these scenarios. Additionally, the Landlock sandbox application now includes more detailed logging, promoting a debug message to a warning when the sandbox is unavailable in BestEffort compatibility mode. The install.sh script has also been updated to allow skipping checksum verification via an environment variable or CLI flag, and it now enforces stricter checksum verification by default, failing if checksums are missing or verification tools are not found. No feedback was provided in the review comments.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 26, 2026

Greptile Summary

This PR hardens the install script by making checksum verification mandatory — previously both a missing sha256sum/shasum binary and a missing checksums file were silently skipped with a warning. An explicit --no-verify-checksum CLI flag and OPENSHELL_NO_VERIFY environment variable are added for intentional opt-out, and the grep-based checksum lookup is replaced with an awk field-equality match to avoid regex misinterpretation of filenames.

Key changes:

  • verify_checksum() now calls error (exits 1) instead of warn + return 0 when no checksum tool or no checksum entry is found.
  • main() errors out when the checksums file download fails instead of silently proceeding.
  • OPENSHELL_NO_VERIFY is normalised to accept common truthy strings (1, true, yes, y, case-insensitive), addressing the prior review concern about =true being silently ignored.
  • A new e2e test test_skip_checksum_env in sh_test.sh verifies the skip path end-to-end.

Remaining observations:

  • The file header comment and usage() help text still describe OPENSHELL_NO_VERIFY as Set to \"1\", but the implementation now accepts true, yes, and y as well.
  • The strict $2 == fname awk field match does not handle binary-mode checksum entries where sha256sum --binary prefixes the filename with *.

Confidence Score: 4/5

Safe to merge with one small logic gap: the awk checksum lookup doesn't handle binary-mode entries with a * filename prefix, which would produce a spurious "no checksum found" error on affected releases.

The two prior P1 findings (OPENSHELL_NO_VERIFY silently ignoring non-"1" values; grep treating filenames as regexes) are both fixed. The remaining findings are P2: a documentation inconsistency where the help text still says "Set to '1'" after the truthy-value expansion, and the awk binary-mode edge case. Score stays at 4 rather than 5 because of the latent correctness gap in checksum lookup.

install.sh — the awk checksum field match on line 189 and documentation on lines 16 and 60.

Important Files Changed

Filename Overview
install.sh Checksum verification hardened to be mandatory; adds --no-verify-checksum flag and OPENSHELL_NO_VERIFY env var with truthy-value normalisation; awk-based checksum lookup fixes regex issue but may miss binary-mode entries; documentation still references only "1" for the env var.
e2e/install/sh_test.sh Adds test_skip_checksum_env() to exercise OPENSHELL_NO_VERIFY=1; correctly installs into an isolated tempdir, verifies the skip message, and cleans up on both success and early-exit paths.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[main starts] --> B[Normalise OPENSHELL_NO_VERIFY\n1/true/yes/y → _skip_checksum=1\nelse → _skip_checksum=0]
    B --> C[Parse CLI flags]
    C --> D{--no-verify-checksum?}
    D -- yes --> E[_skip_checksum=1]
    D -- no --> F[Download binary archive]
    E --> F
    F --> G{Download success?}
    G -- no --> H[error: failed to download]
    G -- yes --> I{_skip_checksum == 1?}
    I -- yes --> J[warn: checksum verification skipped]
    I -- no --> K[Download checksums file]
    K --> L{Download success?}
    L -- no --> M[error: failed to download checksums file]
    L -- yes --> N[awk: look up hash by filename]
    N --> O{Hash found?}
    O -- no --> P[error: no checksum found]
    O -- yes --> Q{shasum or sha256sum available?}
    Q -- no --> R[error: tool not found]
    Q -- yes --> S[Run hash check]
    S --> T{Match?}
    T -- no --> U[error: checksum verification failed]
    T -- yes --> V[Extract and install binary]
    J --> V
Loading

Reviews (1): Last reviewed commit: "fix(install): accept common truthy value..." | Re-trigger Greptile

Comment on lines +263 to +274
if let (Err(err), Some(fallback_body)) = (&result, probe.fallback_body) {
if err.kind == ValidationFailureKind::RequestShape {
return try_validation_request(
client,
route,
probe.path,
probe.protocol,
headers,
fallback_body,
)
.await;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Fallback triggers on 404/405, not just 400

The fallback from max_completion_tokens to max_tokens is semantically meaningful only for an HTTP 400 "unsupported parameter" response. However, ValidationFailureKind::RequestShape is assigned to 400, 404, 405, and 422 (see lines 349–350 in try_validation_request). A 404 (endpoint not found) or 405 (method not allowed) means the entire path is wrong — changing the body parameter won't help — yet the code will fire an extra try_validation_request before finally returning an error.

This adds unnecessary latency and a spurious second request on every misconfigured endpoint. Consider narrowing the guard to specifically detect a 400, or introduce a dedicated variant like ValidationFailureKind::UnsupportedParameter set only on HTTP 400, and guard the fallback on that flag instead of the broader RequestShape kind.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Makes installation checksum verification mandatory by default (with explicit opt-out), and updates backend validation probing to handle OpenAI’s newer max_completion_tokens parameter while improving Landlock sandbox logging.

Changes:

  • install.sh: Fail hard when checksums tooling/entries or checksums download are missing; add --no-verify-checksum / OPENSHELL_NO_VERIFY=1 opt-out and update usage text.
  • openshell-router: Switch OpenAI chat validation probe to max_completion_tokens with a fallback retry using max_tokens on request-shape failures; add targeted tests.
  • openshell-sandbox: Add higher-signal logs when applying Landlock and when Landlock is unavailable in best-effort mode.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
install.sh Enforces checksum verification by default and adds explicit opt-out mechanisms.
crates/openshell-server/src/inference.rs Updates test expectations to match the new OpenAI validation probe parameter.
crates/openshell-sandbox/src/sandbox/linux/landlock.rs Adds additional info/warn logging around Landlock application and fallback behavior.
crates/openshell-router/src/backend.rs Updates OpenAI chat validation probe payload + adds fallback retry logic and tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

install.sh Outdated
error "checksum verification failed for ${_filename}"
fi
else
error "failed to download checksums file from ${_checksums_url} (set OPENSHELL_NO_VERIFY=1 to skip verification)"
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message suggests only OPENSHELL_NO_VERIFY=1 as the opt-out. Since the script now supports --no-verify-checksum, it would be clearer to mention both opt-out mechanisms here too.

Suggested change
error "failed to download checksums file from ${_checksums_url} (set OPENSHELL_NO_VERIFY=1 to skip verification)"
error "failed to download checksums file from ${_checksums_url} (set OPENSHELL_NO_VERIFY=1 or use --no-verify-checksum to skip verification)"

Copilot uses AI. Check for mistakes.
Comment on lines +34 to +38
/// Alternate body to try when the primary probe fails with HTTP 400.
/// Used for OpenAI chat completions where newer models require
/// `max_completion_tokens` while legacy/self-hosted backends only
/// accept `max_tokens`.
fallback_body: Option<bytes::Bytes>,
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment says the fallback is only used when the primary probe fails with HTTP 400, but the retry logic is keyed off ValidationFailureKind::RequestShape (which can also be 404/405/422). Please update the wording to match the actual behavior (e.g., “request-shape error”) or tighten the retry condition if you truly only want to retry on 400.

Copilot uses AI. Check for mistakes.
Comment on lines +259 to +265
// If the primary probe failed with a request-shape error (HTTP 400) and
// there is a fallback body, retry with the alternate token parameter.
// This handles the split between `max_completion_tokens` (GPT-5+) and
// `max_tokens` (legacy/self-hosted backends).
if let (Err(err), Some(fallback_body)) = (&result, probe.fallback_body) {
if err.kind == ValidationFailureKind::RequestShape {
return try_validation_request(
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments say the fallback retry happens only for HTTP 400, but the code retries whenever err.kind == ValidationFailureKind::RequestShape (which is also used for 404/405/422 in try_validation_request). Either adjust the comment to describe “request-shape” failures, or change the condition to only retry on 400 if that’s the intent.

Copilot uses AI. Check for mistakes.
Comment on lines +171 to 178
// Use max_completion_tokens (modern OpenAI parameter, required by GPT-5+)
// with max_tokens as fallback for legacy/self-hosted backends.
return Ok(ValidationProbe {
path: "/v1/chat/completions",
protocol: "openai_chat_completions",
body: bytes::Bytes::from_static(
br#"{"messages":[{"role":"user","content":"ping"}],"max_tokens":32}"#,
br#"{"messages":[{"role":"user","content":"ping"}],"max_completion_tokens":32}"#,
),
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR title/description are scoped to install.sh checksum enforcement, but this PR also changes router backend validation behavior (max_completion_tokens + fallback) and updates Landlock logging. Please update the PR description to reflect these additional behavioral changes, or split them into a separate PR so the install-script change can be reviewed/rolled back independently.

Copilot uses AI. Check for mistakes.
install.sh Outdated
else
warn "sha256sum/shasum not found, skipping checksum verification"
return 0
error "sha256sum or shasum is required for checksum verification (install coreutils or set OPENSHELL_NO_VERIFY=1 to skip)"
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error text only points users at OPENSHELL_NO_VERIFY=1, but this script also supports --no-verify-checksum. Consider mentioning the CLI flag here as an equivalent opt-out so users running ./install.sh ... see the right remediation.

Suggested change
error "sha256sum or shasum is required for checksum verification (install coreutils or set OPENSHELL_NO_VERIFY=1 to skip)"
error "sha256sum or shasum is required for checksum verification (install coreutils, set OPENSHELL_NO_VERIFY=1, or pass --no-verify-checksum to skip)"

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
install.sh (1)

189-201: Correctly makes verification mandatory with clear error messages.

The conversion from warn + return 0 to error (exit) aligns with the PR objective of mandatory verification. The error messages helpfully guide users toward the opt-out mechanism if needed.

Optional hardening: Consider using grep -F for fixed string matching to avoid regex interpretation of dots in the filename.

,

🛡️ Optional: Use fixed-string grep
-  _vc_expected="$(grep "$_vc_filename" "$_vc_checksums" | awk '{print $1}')"
+  _vc_expected="$(grep -F "$_vc_filename" "$_vc_checksums" | awk '{print $1}')"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 189 - 201, The checksum lookup using grep
"$_vc_filename" in the assignment to _vc_expected can misinterpret regex
metacharacters in filenames; change the grep invocation to fixed-string mode
(grep -F) when matching $_vc_filename against $_vc_checksums, keeping the rest
of the flow intact (variables _vc_expected, _vc_filename, _vc_checksums) and
preserving the mandatory verification/error behavior via the has_cmd checks and
error calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/openshell-router/src/backend.rs`:
- Around line 259-274: The current retry uses
ValidationFailureKind::RequestShape for all request-shape failures, which also
includes 404/405 path/method errors; update the conditional guarding the
fallback retry so it only retries when the failure is due to a request
body/parameter shape mismatch (not path/method errors). Concretely, in the block
that checks if let (Err(err), Some(fallback_body)) = (&result,
probe.fallback_body) { ... }, replace the plain err.kind ==
ValidationFailureKind::RequestShape check with a more specific predicate that
detects a body-shape failure (e.g., inspect an error field like err.status_code
to exclude 404/405 or use an err.shape_kind/is_body_shape helper) and only call
try_validation_request(client, route, probe.path, probe.protocol, headers,
fallback_body). Ensure you reference ValidationFailureKind::RequestShape,
try_validation_request, probe.fallback_body, probe.path and probe.protocol when
making the change.
- Around line 591-605: The test verify_non_chat_completions_no_fallback doesn't
assert the mock was called exactly once, so it can pass even if retries occur;
update the mock definition for mock_server (the Mock::given(...) chain that
responds_with(ResponseTemplate::new(400)...) ) to include an explicit
request-count assertion like expect(1) before mounting to ensure the
anthropic_messages probe is not retried and the test enforces a single request.

---

Nitpick comments:
In `@install.sh`:
- Around line 189-201: The checksum lookup using grep "$_vc_filename" in the
assignment to _vc_expected can misinterpret regex metacharacters in filenames;
change the grep invocation to fixed-string mode (grep -F) when matching
$_vc_filename against $_vc_checksums, keeping the rest of the flow intact
(variables _vc_expected, _vc_filename, _vc_checksums) and preserving the
mandatory verification/error behavior via the has_cmd checks and error calls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 15eca818-df29-449f-bfec-ab6126b171fc

📥 Commits

Reviewing files that changed from the base of the PR and between bd7b388 and 817c8c6.

📒 Files selected for processing (4)
  • crates/openshell-router/src/backend.rs
  • crates/openshell-sandbox/src/sandbox/linux/landlock.rs
  • crates/openshell-server/src/inference.rs
  • install.sh

Comment on lines +259 to +274
// If the primary probe failed with a request-shape error (HTTP 400) and
// there is a fallback body, retry with the alternate token parameter.
// This handles the split between `max_completion_tokens` (GPT-5+) and
// `max_tokens` (legacy/self-hosted backends).
if let (Err(err), Some(fallback_body)) = (&result, probe.fallback_body) {
if err.kind == ValidationFailureKind::RequestShape {
return try_validation_request(
client,
route,
probe.path,
probe.protocol,
headers,
fallback_body,
)
.await;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Narrow the fallback retry to body-shape failures.

Line 264 keys off ValidationFailureKind::RequestShape, but try_validation_request() also classifies 404 and 405 that way. Switching max_completion_tokens to max_tokens cannot recover from a bad path or method, so misconfigured base URLs now incur a second POST before failing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/openshell-router/src/backend.rs` around lines 259 - 274, The current
retry uses ValidationFailureKind::RequestShape for all request-shape failures,
which also includes 404/405 path/method errors; update the conditional guarding
the fallback retry so it only retries when the failure is due to a request
body/parameter shape mismatch (not path/method errors). Concretely, in the block
that checks if let (Err(err), Some(fallback_body)) = (&result,
probe.fallback_body) { ... }, replace the plain err.kind ==
ValidationFailureKind::RequestShape check with a more specific predicate that
detects a body-shape failure (e.g., inspect an error field like err.status_code
to exclude 404/405 or use an err.shape_kind/is_body_shape helper) and only call
try_validation_request(client, route, probe.path, probe.protocol, headers,
fallback_body). Ensure you reference ValidationFailureKind::RequestShape,
try_validation_request, probe.fallback_body, probe.path and probe.protocol when
making the change.

Comment on lines +591 to +605
/// Non-chat-completions probes (e.g. anthropic_messages) should not
/// have a fallback — a 400 remains a hard failure.
#[tokio::test]
async fn verify_non_chat_completions_no_fallback() {
let mock_server = MockServer::start().await;
let route = test_route(
&mock_server.uri(),
&["anthropic_messages"],
AuthHeader::Custom("x-api-key"),
);

Mock::given(method("POST"))
.and(path("/v1/messages"))
.respond_with(ResponseTemplate::new(400).set_body_string("bad request"))
.mount(&mock_server)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

This test doesn't actually prove “no fallback”.

Without expect(1) on the mock, the test still passes if the anthropic probe is retried and receives another 400. Add an explicit request-count assertion so this locks in the behavior the docstring describes.

Possible tightening
         Mock::given(method("POST"))
             .and(path("/v1/messages"))
             .respond_with(ResponseTemplate::new(400).set_body_string("bad request"))
+            .expect(1)
             .mount(&mock_server)
             .await;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Non-chat-completions probes (e.g. anthropic_messages) should not
/// have a fallback — a 400 remains a hard failure.
#[tokio::test]
async fn verify_non_chat_completions_no_fallback() {
let mock_server = MockServer::start().await;
let route = test_route(
&mock_server.uri(),
&["anthropic_messages"],
AuthHeader::Custom("x-api-key"),
);
Mock::given(method("POST"))
.and(path("/v1/messages"))
.respond_with(ResponseTemplate::new(400).set_body_string("bad request"))
.mount(&mock_server)
/// Non-chat-completions probes (e.g. anthropic_messages) should not
/// have a fallback — a 400 remains a hard failure.
#[tokio::test]
async fn verify_non_chat_completions_no_fallback() {
let mock_server = MockServer::start().await;
let route = test_route(
&mock_server.uri(),
&["anthropic_messages"],
AuthHeader::Custom("x-api-key"),
);
Mock::given(method("POST"))
.and(path("/v1/messages"))
.respond_with(ResponseTemplate::new(400).set_body_string("bad request"))
.expect(1)
.mount(&mock_server)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/openshell-router/src/backend.rs` around lines 591 - 605, The test
verify_non_chat_completions_no_fallback doesn't assert the mock was called
exactly once, so it can pass even if retries occur; update the mock definition
for mock_server (the Mock::given(...) chain that
responds_with(ResponseTemplate::new(400)...) ) to include an explicit
request-count assertion like expect(1) before mounting to ensure the
anthropic_messages probe is not retried and the test enforces a single request.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
install.sh (1)

267-278: Consider accepting additional truthy values for OPENSHELL_NO_VERIFY.

Currently only "1" skips verification. Users might intuitively try OPENSHELL_NO_VERIFY=true or OPENSHELL_NO_VERIFY=yes, which would silently not skip (since they don't equal "1"), potentially causing confusion when verification still fails.

🔧 Optional: Accept common truthy values
-  if [ "$_skip_checksum" = "1" ]; then
+  case "$_skip_checksum" in
+    1|true|yes|TRUE|YES)
+      warn "checksum verification skipped (OPENSHELL_NO_VERIFY=1 or --no-verify-checksum)"
+      ;;
+    *)
+      info "verifying checksum..."
+      if download "$_checksums_url" "${_tmpdir}/checksums.txt"; then
+        if ! verify_checksum "${_tmpdir}/${_filename}" "${_tmpdir}/checksums.txt" "$_filename"; then
+          error "checksum verification failed for ${_filename}"
+        fi
+      else
+        error "failed to download checksums file from ${_checksums_url} (set OPENSHELL_NO_VERIFY=1 or use --no-verify-checksum to skip verification)"
+      fi
+      ;;
+  esac
-    warn "checksum verification skipped (OPENSHELL_NO_VERIFY=1 or --no-verify-checksum)"
-  else
-    info "verifying checksum..."
-    if download "$_checksums_url" "${_tmpdir}/checksums.txt"; then
-      if ! verify_checksum "${_tmpdir}/${_filename}" "${_tmpdir}/checksums.txt" "$_filename"; then
-        error "checksum verification failed for ${_filename}"
-      fi
-    else
-      error "failed to download checksums file from ${_checksums_url} (set OPENSHELL_NO_VERIFY=1 or use --no-verify-checksum to skip verification)"
-    fi
-  fi

Alternatively, keep strict "1" matching but update documentation to explicitly state only "1" is accepted.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 267 - 278, The current check in the install.sh
branch uses exact equality to "1" for _skip_checksum/OPENSHELL_NO_VERIFY; update
the condition in the install script so it accepts common truthy values (e.g.,
"1", "true", "yes", "y") case-insensitively instead of only "1". Locate the
conditional that tests _skip_checksum / OPENSHELL_NO_VERIFY in install.sh (the
if [ "$_skip_checksum" = "1" ] block) and replace it with a check that
normalizes/lowercases the value and matches against the allowed truthy set (or
use a regex like ^(1|true|yes|y)$) so users can set OPENSHELL_NO_VERIFY=true or
yes to skip checksum verification. Ensure behavior remains unchanged for
falsy/absent values.
e2e/install/sh_test.sh (1)

71-92: Minor: Temp directory not cleaned up after test.

The _skip_dir created via mktemp -d is not removed after the test completes. While this is minor for e2e tests (OS cleans /tmp eventually), consider adding cleanup for consistency with other test patterns or if tests run frequently in CI.

🧹 Optional cleanup addition
 test_skip_checksum_env() {
   printf 'TEST: OPENSHELL_NO_VERIFY=1 skips checksum verification\n'

-  _skip_dir="$(mktemp -d)/bin"
+  _skip_base="$(mktemp -d)"
+  _skip_dir="${_skip_base}/bin"
   _skip_output="$(OPENSHELL_NO_VERIFY=1 \
     OPENSHELL_INSTALL_DIR="$_skip_dir" \
     SHELL="/bin/sh" \
     PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" \
     sh "$INSTALL_SCRIPT" 2>&1)" || {
     fail "install succeeds with OPENSHELL_NO_VERIFY=1" "exit code: $?"
+    rm -rf "$_skip_base"
     return 1
   }

   assert_output_contains "$_skip_output" "checksum verification skipped" \
     "shows checksum skip message"

   if [ -f "$_skip_dir/openshell" ]; then
     pass "binary installed with checksum skip"
   else
     fail "binary installed with checksum skip" "not found at $_skip_dir/openshell"
   fi
+  rm -rf "$_skip_base"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/install/sh_test.sh` around lines 71 - 92, The test_skip_checksum_env
function creates a temporary directory in _skip_dir via mktemp -d but never
removes it; update test_skip_checksum_env to clean the temp directory after the
test finishes (and on errors) by removing _skip_dir (e.g., rm -rf "$_skip_dir")
or register a trap to delete _skip_dir on EXIT so the temp dir is removed
whether the test passes or fails; keep the cleanup adjacent to the existing
asserts and use the same _skip_dir variable name to locate the removal.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/install/sh_test.sh`:
- Around line 71-92: The test_skip_checksum_env function creates a temporary
directory in _skip_dir via mktemp -d but never removes it; update
test_skip_checksum_env to clean the temp directory after the test finishes (and
on errors) by removing _skip_dir (e.g., rm -rf "$_skip_dir") or register a trap
to delete _skip_dir on EXIT so the temp dir is removed whether the test passes
or fails; keep the cleanup adjacent to the existing asserts and use the same
_skip_dir variable name to locate the removal.

In `@install.sh`:
- Around line 267-278: The current check in the install.sh branch uses exact
equality to "1" for _skip_checksum/OPENSHELL_NO_VERIFY; update the condition in
the install script so it accepts common truthy values (e.g., "1", "true", "yes",
"y") case-insensitively instead of only "1". Locate the conditional that tests
_skip_checksum / OPENSHELL_NO_VERIFY in install.sh (the if [ "$_skip_checksum" =
"1" ] block) and replace it with a check that normalizes/lowercases the value
and matches against the allowed truthy set (or use a regex like
^(1|true|yes|y)$) so users can set OPENSHELL_NO_VERIFY=true or yes to skip
checksum verification. Ensure behavior remains unchanged for falsy/absent
values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1e7e072f-3225-494a-aa08-f01de04df652

📥 Commits

Reviewing files that changed from the base of the PR and between 817c8c6 and a511e3d.

📒 Files selected for processing (2)
  • e2e/install/sh_test.sh
  • install.sh

@areporeporepo
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@areporeporepo
Copy link
Copy Markdown
Owner Author

@gemini-code-assist review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fallback mechanism for OpenAI chat completion probes in the router to accommodate differences between max_completion_tokens (for newer models) and max_tokens (for legacy/self-hosted backends). It adds a fallback_body field to ValidationProbe and modifies the validation logic to retry with the fallback if the primary probe fails with an HTTP 400 error. New tests have been added to cover this behavior. Additionally, the Landlock sandbox application now includes more informative logging (info/warn) regarding its status and compatibility. The install.sh script has been enhanced to allow skipping checksum verification via an OPENSHELL_NO_VERIFY environment variable or a --no-verify-checksum CLI flag, with stricter failure conditions if checksums or required tools are missing. A new end-to-end test verifies this skip functionality. There is no feedback to provide.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +72 to +73
# Skip checksum verification (not recommended)
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | OPENSHELL_NO_VERIFY=1 sh
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usage() documents the --no-verify-checksum flag in OPTIONS, but the EXAMPLES section only shows opting out via OPENSHELL_NO_VERIFY. Consider adding an example invocation that uses --no-verify-checksum as well, so users discover the CLI form without reading the whole help text.

Suggested change
# Skip checksum verification (not recommended)
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | OPENSHELL_NO_VERIFY=1 sh
# Skip checksum verification via environment variable (not recommended)
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | OPENSHELL_NO_VERIFY=1 sh
# Skip checksum verification via CLI flag (not recommended)
./install.sh --no-verify-checksum

Copilot uses AI. Check for mistakes.
Comment on lines 239 to 241
case "$arg" in
--help)
usage
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new --no-verify-checksum flag is introduced here, but the e2e install tests only cover the OPENSHELL_NO_VERIFY=1 path. Adding an e2e case for the CLI flag would help prevent regressions in argument parsing and precedence vs the env var.

Copilot uses AI. Check for mistakes.
Comment on lines +259 to +276
// If the primary probe failed with a request-shape error (HTTP 400) and
// there is a fallback body, retry with the alternate token parameter.
// This handles the split between `max_completion_tokens` (GPT-5+) and
// `max_tokens` (legacy/self-hosted backends).
if let (Err(err), Some(fallback_body)) = (&result, probe.fallback_body) {
if err.kind == ValidationFailureKind::RequestShape {
return try_validation_request(
client,
route,
probe.path,
probe.protocol,
headers,
fallback_body,
)
.await;
}
}

Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The retry condition uses err.kind == ValidationFailureKind::RequestShape, but try_validation_request() classifies 400/404/405/422 as RequestShape. That means this fallback will also retry on 404/405 (wrong path/method), where changing the token parameter can’t help and just adds an extra request. Consider carrying the HTTP status through ValidationFailure (or returning it alongside the failure) so the fallback can be limited to statuses that actually indicate a schema/parameter mismatch (e.g. 400/422).

Suggested change
// If the primary probe failed with a request-shape error (HTTP 400) and
// there is a fallback body, retry with the alternate token parameter.
// This handles the split between `max_completion_tokens` (GPT-5+) and
// `max_tokens` (legacy/self-hosted backends).
if let (Err(err), Some(fallback_body)) = (&result, probe.fallback_body) {
if err.kind == ValidationFailureKind::RequestShape {
return try_validation_request(
client,
route,
probe.path,
probe.protocol,
headers,
fallback_body,
)
.await;
}
}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
install.sh (2)

16-17: Keep the help text aligned with the accepted env values.

main() accepts 1/true/yes/y, but the inline docs and usage only advertise "1". Updating the wording here would keep the documented contract in sync with the implementation.

📝 Suggested wording
-#   OPENSHELL_NO_VERIFY   - Set to "1" to skip checksum verification (not recommended)
+#   OPENSHELL_NO_VERIFY   - Set to 1/true/yes/y to skip checksum verification (not recommended)
...
-    OPENSHELL_NO_VERIFY     Set to "1" to skip checksum verification (not recommended)
+    OPENSHELL_NO_VERIFY     Set to 1/true/yes/y to skip checksum verification (not recommended)

Also applies to: 54-60, 72-73

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 16 - 17, Update the help/usage text for
OPENSHELL_NO_VERIFY to match the values accepted by main() by listing
"1/true/yes/y" (not just "1"); locate the usage/help strings that mention
OPENSHELL_NO_VERIFY (the inline docs and usage output) and change their wording
to state the full accepted set ("1/true/yes/y") and/or equivalent
case-insensitive true values so the documented contract matches the main()
parsing logic; apply the same wording change to the other help occurrences that
reference OPENSHELL_NO_VERIFY in the script.

272-282: Add regression coverage for the new hard-fail branches.

This block is now the core security boundary. A focused test for checksum-file download failure, plus one for a verification failure path, would make it much harder to regress back to warning-and-continue behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 272 - 282, Add regression tests that exercise the
hard-fail branches in the checksum verification block: one test should simulate
download "$_checksums_url" failing (e.g., mock the download function or the
network call) and assert the script invokes error and exits non-zero, and a
second test should simulate verify_checksum returning false for
"${_tmpdir}/${_filename}" with "${_tmpdir}/checksums.txt" and assert error is
invoked and the script exits non-zero; target the logic that checks
$_skip_checksum, calls download and verify_checksum and uses error/warn/info so
your tests mock/stub download and verify_checksum and verify the error path is
taken rather than allowing a warning-and-continue behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@install.sh`:
- Around line 16-17: Update the help/usage text for OPENSHELL_NO_VERIFY to match
the values accepted by main() by listing "1/true/yes/y" (not just "1"); locate
the usage/help strings that mention OPENSHELL_NO_VERIFY (the inline docs and
usage output) and change their wording to state the full accepted set
("1/true/yes/y") and/or equivalent case-insensitive true values so the
documented contract matches the main() parsing logic; apply the same wording
change to the other help occurrences that reference OPENSHELL_NO_VERIFY in the
script.
- Around line 272-282: Add regression tests that exercise the hard-fail branches
in the checksum verification block: one test should simulate download
"$_checksums_url" failing (e.g., mock the download function or the network call)
and assert the script invokes error and exits non-zero, and a second test should
simulate verify_checksum returning false for "${_tmpdir}/${_filename}" with
"${_tmpdir}/checksums.txt" and assert error is invoked and the script exits
non-zero; target the logic that checks $_skip_checksum, calls download and
verify_checksum and uses error/warn/info so your tests mock/stub download and
verify_checksum and verify the error path is taken rather than allowing a
warning-and-continue behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9d7c7bcd-2995-45f6-9369-b4eba7a70727

📥 Commits

Reviewing files that changed from the base of the PR and between a511e3d and 7cbf39f.

📒 Files selected for processing (2)
  • e2e/install/sh_test.sh
  • install.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e/install/sh_test.sh

areporeporepo and others added 3 commits March 30, 2026 18:43
- verify_checksum() now errors instead of warning when sha256sum/shasum
  is unavailable or when no checksum entry exists for the archive
- main() now errors when the checksums file cannot be downloaded
- Add --no-verify-checksum flag and OPENSHELL_NO_VERIFY env var for
  explicit opt-out in environments where verification is not feasible
- Update usage() with new flag, env var, and example

Previously, an attacker who could manipulate the download (MITM without
HTTPS pinning) could serve a binary without the checksum file, and the
installer would proceed silently. Now the installer fails loudly unless
the operator explicitly opts out.

Closes NVIDIA#590

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: areporeporepo <areporeporepo@users.noreply.github.com>
- Use awk exact-field match instead of grep regex for checksum lookup
- Include both opt-out mechanisms (env var + flag) in all error messages
- Add e2e test for OPENSHELL_NO_VERIFY=1 checksum skip path

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: areporeporepo <areporeporepo@users.noreply.github.com>
- Accept 1, true, yes, y (case-insensitive) for OPENSHELL_NO_VERIFY
- Clean up temp directory in e2e checksum skip test

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: areporeporepo <areporeporepo@users.noreply.github.com>
@areporeporepo areporeporepo force-pushed the fix/install-mandatory-checksum branch from 7cbf39f to 4336c0c Compare March 31, 2026 01:44
# Environment variables:
# OPENSHELL_VERSION - Release tag to install (default: latest tagged release)
# OPENSHELL_INSTALL_DIR - Directory to install into (default: ~/.local/bin)
# OPENSHELL_NO_VERIFY - Set to "1" to skip checksum verification (not recommended)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Documentation lags behind expanded truthy values

The header comment on line 16 says Set to "1" and the usage() help text on line 60 repeats the same phrasing:

OPENSHELL_NO_VERIFY     Set to "1" to skip checksum verification (not recommended)

However, main() now normalises the variable to accept 1, true, yes, and y (case-insensitive). Both lines (16 and 60) should be updated to list the full set of accepted truthy values.

Suggested change
# OPENSHELL_NO_VERIFY - Set to "1" to skip checksum verification (not recommended)
# OPENSHELL_NO_VERIFY - Set to "1", "true", "yes", or "y" to skip checksum verification (not recommended)

_vc_filename="$3"

_vc_expected="$(grep "$_vc_filename" "$_vc_checksums" | awk '{print $1}')"
_vc_expected="$(awk -v fname="$_vc_filename" '$2 == fname { print $1 }' "$_vc_checksums")"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 awk '$2 == fname' silently misses binary-mode checksum entries

The awk approach is a solid fix for the previous grep regex-interpretation concern, but it introduces a stricter format requirement. When sha256sum generates a checksums file in binary mode the line looks like:

abc123...  *openshell-aarch64-unknown-linux-musl.tar.gz

awk's default field split gives $1 = abc123..., $2 = *openshell-... — with the leading asterisk — so $2 == fname never matches the plain filename, and the script exits with "no checksum found" even though a valid entry is present.

A field-aware approach that strips a leading * would be robust to both text-mode and binary-mode:

_vc_expected="$(awk -v fname="$_vc_filename" '{ f=$2; sub(/^\*/, "", f); if (f == fname) print $1 }' "$_vc_checksums")"

This retains exact-filename matching (no regex) while tolerating the binary-mode asterisk prefix.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
install.sh (1)

16-16: Document all accepted OPENSHELL_NO_VERIFY truthy values.

Line 60 says “set to 1”, but Lines 232-234 also accept true/yes/y. Consider documenting the full accepted set to match runtime behavior.

💡 Suggested doc tweak
-#   OPENSHELL_NO_VERIFY   - Set to "1" to skip checksum verification (not recommended)
+#   OPENSHELL_NO_VERIFY   - Set to "1", "true", "yes", or "y" to skip checksum verification (not recommended)
...
-    OPENSHELL_NO_VERIFY     Set to "1" to skip checksum verification (not recommended)
+    OPENSHELL_NO_VERIFY     Set to "1"/"true"/"yes"/"y" to skip checksum verification (not recommended)

Also applies to: 60-60, 230-235

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` at line 16, Update the install.sh comment for OPENSHELL_NO_VERIFY
to list all accepted truthy values (not just "1") so the docs match runtime
behavior: mention that the installer treats "1", "true", "yes", and "y"
(case-insensitive) as truthy; reference OPENSHELL_NO_VERIFY in the comment near
the top of the script and ensure the same wording is used for the help/usage
lines around where OPENSHELL_NO_VERIFY is parsed (the block that checks the
variable at runtime).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@install.sh`:
- Line 16: Update the install.sh comment for OPENSHELL_NO_VERIFY to list all
accepted truthy values (not just "1") so the docs match runtime behavior:
mention that the installer treats "1", "true", "yes", and "y" (case-insensitive)
as truthy; reference OPENSHELL_NO_VERIFY in the comment near the top of the
script and ensure the same wording is used for the help/usage lines around where
OPENSHELL_NO_VERIFY is parsed (the block that checks the variable at runtime).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d3bd85ec-a2ea-4b89-83a4-a06d554773a0

📥 Commits

Reviewing files that changed from the base of the PR and between 7cbf39f and 4336c0c.

📒 Files selected for processing (2)
  • e2e/install/sh_test.sh
  • install.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e/install/sh_test.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sec(install): checksum verification silently skipped when sha256sum unavailable

2 participants