{"record":{"id":"4a3eb55eb678ec7f","repo":"jdx/mise","slug":"unsupported-github-operation","errorCode":null,"errorMessage":"unsupported GitHub operation","messagePattern":"unsupported GitHub operation","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/github_relay.rs","lineNumber":202,"sourceCode":"        if decoded.is_empty()\n            || matches!(decoded.as_ref(), \".\" | \"..\")\n            || decoded.contains(['/', '\\\\', '%'])\n            || decoded.chars().any(char::is_control)\n        {\n            bail!(\"invalid relay path\");\n        }\n    }\n    Ok(())\n}\n\n#[cfg(any(unix, test))]\nfn authorize(scope: &Scope, method: &str, path: &str, query: Option<&str>) -> Result<Target> {\n    validate_path(path)?;\n    let p: Vec<_> = path.split('/').collect();\n    let (owner, repo) = match p.as_slice() {\n        [\"api\", \"repos\", owner, repo, ..] => (*owner, *repo),\n        [\"git\" | \"web\", owner, repo, ..] => (*owner, repo.strip_suffix(\".git\").unwrap_or(repo)),\n        _ => bail!(\"unsupported GitHub operation\"),\n    };\n    let name = repository(&format!(\"{owner}/{repo}\"))?;\n    if !scope.permits(&name) {\n        bail!(\"repository is outside the approved relay scope\");\n    }\n    let git = p[0] == \"git\";\n    let allowed = match p.as_slice() {\n        [\"git\", _, _, \"info\", \"refs\"] => {\n            method == \"GET\" && query == Some(\"service=git-upload-pack\")\n        }\n        [\"git\", _, _, \"git-upload-pack\"] => method == \"POST\" && query.is_none(),\n        [\"api\", \"repos\", _, _] => method == \"GET\" || method == \"HEAD\",\n        [\"api\", \"repos\", _, _, \"git\", kind, ..] => {\n            matches!(*kind, \"refs\" | \"matching-refs\") && matches!(method, \"GET\" | \"HEAD\")\n        }\n        [\"api\", \"repos\", _, _, kind, ..] => {\n            matches!(\n                *kind,","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/github_relay.rs#L184-L220","documentation":"`authorize` only recognizes three relayed URL shapes: API repo calls (`/api/repos/{owner}/{repo}/...`), git smart-HTTP paths (`/git/{owner}/{repo}/...`), and web download paths (`/web/{owner}/{repo}/...`). Any path that does not match one of these prefixes fails with this error before any scope or method check runs.","triggerScenarios":"Calling `operation`/`forward` with paths like `/user`, `/orgs/foo`, `/api/graphql`, `/search/repositories`, a bare `/`, or a misspelled prefix like `/API/repos/...` or `/gits/owner/repo`.","commonSituations":"A client library building GitHub API URLs against endpoints the relay deliberately does not proxy (user, org, search, GraphQL); switching from download URLs to API endpoints the relay doesn't allow; typos in the prefix.","solutions":["Restrict requests to `/api/repos/{owner}/{repo}/...`, `/git/{owner}/{repo}/...`, or `/web/{owner}/{repo}/...` paths.","Drop or replace unsupported endpoints (e.g. `/user`, `/search`) — they are outside the relay's read-only repo scope by design.","Fix prefix typos and ensure the path is normalized (no leading host or scheme inside `path`)."],"exampleFix":"// before\nlet target = relay::operation(\"GET\", \"/user\", None)?;\n// after\nlet target = relay::operation(\"GET\", \"/api/repos/octocat/hello-world\", None)?;","handlingStrategy":"validation","validationCode":"fn relayable_path(p: &str) -> bool {\n    let s: Vec<&str> = p.split('/').collect();\n    matches!(s.as_slice(),\n        [\"api\", \"repos\", _, _, ..] | [\"git\", _, _, ..] | [\"web\", _, _, ..])\n}\nassert!(relayable_path(\"/api/repos/o/r\"));\nassert!(!relayable_path(\"/user\"));","typeGuard":null,"tryCatchPattern":"match relay::operation(\"GET\", path, None) {\n    Err(e) if e.to_string().contains(\"unsupported GitHub operation\") => eprintln!(\"endpoint not relayed: {path}\"),\n    Err(e) => return Err(e),\n    Ok(t) => t,\n}","preventionTips":["Restrict client code to repo-scoped API endpoints the relay supports.","Keep a list of relayed path prefixes and route other GitHub calls outside the relay.","Normalize paths before calling (no host/scheme, correct casing for prefixes)."],"tags":["github","relay","routing","validation"],"backgroundTag":"unsupported-operation","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}