Fix GitHub App repo visibility check: treat 401/403 as private

The is_repo_public function called GET /repos/{owner}/{repo} with
the App JWT, but GitHub returns 401 for App JWTs on the repos
endpoint (they need an installation token). Previously this 401
was treated as an auth error, failing sandbox init.

Now 401 and 403 are treated like 404: assume private and proceed
to create an installation access token, which has the right perms.

Also add preflight phase to the DOT test runner.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-06 15:44:00 -05:00
parent a58bebff8b
commit 942f717eb4
2 changed files with 24 additions and 4 deletions

View file

@ -60,8 +60,9 @@ pub fn sign_app_jwt(app_id: &str, private_key_pem: &str) -> Result<String, Strin
let key = EncodingKey::from_rsa_pem(private_key_pem.as_bytes())
.map_err(|e| format!("Invalid RSA private key: {e}"))?;
encode(&Header::new(Algorithm::RS256), &claims, &key)
.map_err(|e| format!("Failed to sign JWT: {e}"))
let jwt = encode(&Header::new(Algorithm::RS256), &claims, &key)
.map_err(|e| format!("Failed to sign JWT: {e}"))?;
Ok(jwt)
}
/// Check whether a GitHub repository is public using the App JWT.
@ -88,7 +89,13 @@ pub async fn is_repo_public(
.map_err(|e| format!("Failed to check repo visibility: {e}"))?;
let status = response.status();
if status == reqwest::StatusCode::NOT_FOUND {
// 404 = repo not found (or not visible); 401/403 = app JWT can't read repos.
// In all these cases, assume the repo is private and proceed to get an
// installation access token, which WILL have the right permissions.
if status == reqwest::StatusCode::NOT_FOUND
|| status == reqwest::StatusCode::UNAUTHORIZED
|| status == reqwest::StatusCode::FORBIDDEN
{
return Ok(false);
}
if !status.is_success() {

View file

@ -38,6 +38,19 @@ run_one() {
fail=$((fail + 1))
fi
;;
preflight)
# cd into the dot file's directory so relative paths resolve
local target="$dot_name"
[[ -f "$toml" ]] && target="run-${stem}.toml"
if (cd "$dot_dir" && "$ARC" run start "$target" --preflight 2>&1); then
echo " PASS $rel"
pass=$((pass + 1))
else
echo " FAIL $rel"
fail=$((fail + 1))
fi
;;
dry-run|haiku|full)
# cd into the dot file's directory so relative script paths resolve
local target="$dot_name"
@ -56,7 +69,7 @@ run_one() {
fi
;;
*)
echo "Usage: $0 <validate|dry-run|haiku|full>"
echo "Usage: $0 <validate|preflight|dry-run|haiku|full>"
exit 1
;;
esac