Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-yaml
args: ["--unsafe"]
- id: end-of-file-fixer
- id: trailing-whitespace
- id: detect-private-key
exclude: "internal/layers/secrets_test\\.go$|internal/security/scanner_test\\.go$|tests/.*test_.*\\.py$"
- id: check-added-large-files
args: ["--maxkb=1000"]
- id: check-merge-conflict
- id: check-json
- id: check-toml
- id: mixed-line-ending

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.7
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

- repo: local
hooks:
- id: ty
name: ty check
entry: uvx ty check . --ignore unresolved-import --ignore unresolved-attribute
language: system
types: [python]
pass_filenames: false

- repo: https://github.com/PyCQA/bandit
rev: "1.9.4"
hooks:
- id: bandit
args: ["--skip", "B101,B404,B603"]

- repo: https://github.com/zricethezav/gitleaks
rev: v8.30.0
hooks:
- id: gitleaks

- repo: https://github.com/rhysd/actionlint
rev: v1.7.11
hooks:
- id: actionlint
13 changes: 10 additions & 3 deletions 67-claude-github-app-auth/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@
)

if response.status_code != 200:
print(f"Error fetching installations: {response.status_code} {response.text}", file=sys.stderr)
print(
f"Error fetching installations: {response.status_code} {response.text}",
file=sys.stderr,
)
sys.exit(1)

installations = response.json()
Expand All @@ -53,7 +56,9 @@
installation_id = inst["id"]
account = inst.get("account", {})
print(f"Installation ID: {installation_id}")
print(f" Account: {account.get('login', 'N/A')} ({account.get('type', 'N/A')})")
print(
f" Account: {account.get('login', 'N/A')} ({account.get('type', 'N/A')})"
)
print(f" Target type: {inst.get('target_type', 'N/A')}")

# Create an installation access token
Expand All @@ -69,7 +74,9 @@

token_data = token_resp.json()
install_token = token_data["token"]
print(f" Token: {install_token[:12]}... (expires {token_data.get('expires_at', 'N/A')})")
print(
f" Token: {install_token[:12]}... (expires {token_data.get('expires_at', 'N/A')})"
)

# List repositories accessible to this installation token
repos_resp = requests.get(
Expand Down
8 changes: 6 additions & 2 deletions adr46-scanner/scanner/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ def main():
parser = argparse.ArgumentParser(
description="Scan Tekton tasks for ADR-0046 drift (non-task-runner images)",
)
parser.add_argument("repo_path", help="Path to the build-definitions repo (or similar)")
parser.add_argument(
"repo_path", help="Path to the build-definitions repo (or similar)"
)
parser.add_argument("--config", required=True, help="Path to scanner config YAML")
parser.add_argument("--json", dest="json_output", action="store_true", help="Output as JSON")
parser.add_argument(
"--json", dest="json_output", action="store_true", help="Output as JSON"
)
args = parser.parse_args()

config = load_config(args.config)
Expand Down
4 changes: 3 additions & 1 deletion adr46-scanner/tests/test_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ def config():


def _make_task(steps):
return TektonTask(name="test-task", file_path=Path("task/test/0.1/test.yaml"), steps=steps)
return TektonTask(
name="test-task", file_path=Path("task/test/0.1/test.yaml"), steps=steps
)


def test_no_drift_when_using_task_runner(config):
Expand Down
89 changes: 75 additions & 14 deletions agent-scoped-tools-triage/assets/generate_gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,27 @@
# Try to load a nice font, fall back to default
try:
FONT = ImageFont.truetype("/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf", 13)
FONT_BOLD = ImageFont.truetype("/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf", 13)
FONT_SMALL = ImageFont.truetype("/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf", 11)
FONT_TITLE = ImageFont.truetype("/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf", 15)
FONT_BOLD = ImageFont.truetype(
"/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf", 13
)
FONT_SMALL = ImageFont.truetype(
"/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf", 11
)
FONT_TITLE = ImageFont.truetype(
"/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf", 15
)
except OSError:
try:
FONT = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 13)
FONT_BOLD = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 13)
FONT_SMALL = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11)
FONT_TITLE = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 15)
FONT_BOLD = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 13
)
FONT_SMALL = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11
)
FONT_TITLE = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 15
)
except OSError:
FONT = ImageFont.load_default()
FONT_BOLD = FONT
Expand Down Expand Up @@ -103,7 +115,14 @@
ARROWS = {
"launch_gh": ("launcher", "gh_server", "starts", "solid", None, None),
"launch_runner": ("launcher", "agent_runner", "starts", "solid", None, None),
"launch_triage": ("launcher", "agent_runner", "POST /run-agent\n(triage)", "solid", None, None),
"launch_triage": (
"launcher",
"agent_runner",
"POST /run-agent\n(triage)",
"solid",
None,
None,
),
"runner_gateway": (
"agent_runner",
"gateway",
Expand All @@ -113,21 +132,56 @@
None,
),
"gh_api": ("gh_server", "github_api", "scoped API calls", "solid", None, None),
"runner_triage": ("agent_runner", "triage", "creates + runs", "solid", "bottom", "right"),
"triage_gh": ("triage", "gh_server", "GET+POST :8081\nread-write", "dashed", "top", "bottom"),
"triage_runner": ("triage", "agent_runner", "POST /run-agent", "solid", "top", "left"),
"runner_triage": (
"agent_runner",
"triage",
"creates + runs",
"solid",
"bottom",
"right",
),
"triage_gh": (
"triage",
"gh_server",
"GET+POST :8081\nread-write",
"dashed",
"top",
"bottom",
),
"triage_runner": (
"triage",
"agent_runner",
"POST /run-agent",
"solid",
"top",
"left",
),
"runner_dup": ("agent_runner", "dup", "creates + runs", "solid", None, None),
"dup_gh": ("dup", "gh_server", "GET :8081\nread-only", "dashed", None, None),
"runner_comp": ("agent_runner", "comp", "creates + runs", "solid", None, None),
"comp_gh": ("comp", "gh_server", "GET :8081\nread-only", "dashed", None, None),
"comp_web": ("comp", "ext_urls", "HTTPS GET", "solid", None, None),
"runner_repro": ("agent_runner", "repro", "creates + runs\n(bugs only)", "solid", None, None),
"runner_repro": (
"agent_runner",
"repro",
"creates + runs\n(bugs only)",
"solid",
None,
None,
),
"repro_gh": ("repro", "gh_server", "GET :8081\nread-only", "dashed", None, None),
"repro_fs": ("repro", "local_fs", "grep, find, cat", "solid", None, None),
"dup_return": ("dup", "agent_runner", "JSON findings", "data", None, None),
"comp_return": ("comp", "agent_runner", "JSON findings", "data", None, None),
"repro_return": ("repro", "agent_runner", "JSON findings", "data", None, None),
"runner_return": ("agent_runner", "triage", "JSON findings", "data", "bottom", "top"),
"runner_return": (
"agent_runner",
"triage",
"JSON findings",
"data",
"bottom",
"top",
),
}


Expand Down Expand Up @@ -370,7 +424,9 @@ def draw_arrow(
lx = mx - tw // 2
ly = my - len(lines) * (th + 2) // 2 + i * (th + 2) - 2
# White background for readability
draw.rectangle([lx - 2, ly - 1, lx + tw + 2, ly + th + 1], fill=(255, 255, 255, 220))
draw.rectangle(
[lx - 2, ly - 1, lx + tw + 2, ly + th + 1], fill=(255, 255, 255, 220)
)
draw.text((lx, ly), line, fill=col, font=FONT_SMALL)


Expand Down Expand Up @@ -450,7 +506,12 @@ def draw_frame(step_index: int) -> Image.Image:
total = len(STEPS)
indicator = f"Step {step_index + 1}/{total}"
bbox = draw.textbbox((0, 0), indicator, font=FONT_SMALL)
draw.text((W - (bbox[2] - bbox[0]) - 20, 18), indicator, fill=(150, 150, 150), font=FONT_SMALL)
draw.text(
(W - (bbox[2] - bbox[0]) - 20, 18),
indicator,
fill=(150, 150, 150),
font=FONT_SMALL,
)

# Draw sandboxes first (background)
for sb_id in visible_sandboxes:
Expand Down
12 changes: 9 additions & 3 deletions agent-scoped-tools-triage/launcher/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,22 @@ def main() -> None:
# Token source (mutually exclusive)
token_group = parser.add_mutually_exclusive_group()
token_group.add_argument("--token", help="GitHub token (for testing)")
token_group.add_argument("--pem", help="Path to GitHub App PEM key (for production)")
token_group.add_argument(
"--pem", help="Path to GitHub App PEM key (for production)"
)

# GitHub App auth options (only needed with --pem)
parser.add_argument("--client-id", help="GitHub App Client ID")
parser.add_argument("--installation-id", type=int, help="GitHub App Installation ID")
parser.add_argument(
"--installation-id", type=int, help="GitHub App Installation ID"
)
parser.add_argument("--repo-id", type=int, help="Repository ID (for scoped token)")

# Required
parser.add_argument("--repo", required=True, help="Repository in org/repo format")
parser.add_argument("--issue", required=True, type=int, help="Issue number to triage")
parser.add_argument(
"--issue", required=True, type=int, help="Issue number to triage"
)

args = parser.parse_args()

Expand Down
4 changes: 3 additions & 1 deletion agent-scoped-tools-triage/launcher/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ def get_ssh_config(sandbox_name: str) -> str:
return result.stdout


def sandbox_scp(ssh_config_path: str, sandbox_name: str, local: str, remote: str) -> None:
def sandbox_scp(
ssh_config_path: str, sandbox_name: str, local: str, remote: str
) -> None:
"""Copy a file or directory into a sandbox."""
subprocess.run(
[ # nosec B607
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ def log_message(self, format, *args):
def main() -> None:
import argparse

parser = argparse.ArgumentParser(description="REST server for sandboxed agent execution")
parser = argparse.ArgumentParser(
description="REST server for sandboxed agent execution"
)
parser.add_argument(
"--port",
type=int,
Expand All @@ -116,6 +118,11 @@ def main() -> None:
print(f"Error: {name} not set", file=sys.stderr)
sys.exit(1)

assert working_dir is not None
assert owner is not None
assert repo_name is not None
assert issue_number is not None

runner = AgentRunner(
working_dir=Path(working_dir),
owner=owner,
Expand Down
6 changes: 5 additions & 1 deletion agent-scoped-tools-triage/tools/agent-runner/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ def discover_agents(working_dir: Path) -> dict[str, str | None]:
def _get_vertex_env() -> dict[str, str]:
"""Collect Vertex AI environment variables from the host, if present."""
vertex_vars = {}
for key in ("CLAUDE_CODE_USE_VERTEX", "ANTHROPIC_VERTEX_PROJECT_ID", "CLOUD_ML_REGION"):
for key in (
"CLAUDE_CODE_USE_VERTEX",
"ANTHROPIC_VERTEX_PROJECT_ID",
"CLOUD_ML_REGION",
):
val = os.environ.get(key)
if val:
vertex_vars[key] = val
Expand Down
28 changes: 24 additions & 4 deletions agent-scoped-tools-triage/tools/gh-server/gh_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ def do_POST(self):
if re.search(pattern, comment_body, re.IGNORECASE):
self._send_json(
400,
{"error": "Comment appears to contain credentials. Refusing."},
{
"error": "Comment appears to contain credentials. Refusing."
},
)
return

Expand Down Expand Up @@ -213,7 +215,15 @@ def do_POST(self):
labels = ",".join(labels)

result = gh(
["issue", "edit", issue_number, "--repo", allowed_repo, "--add-label", labels],
[
"issue",
"edit",
issue_number,
"--repo",
allowed_repo,
"--add-label",
labels,
],
token,
)
if result.returncode != 0:
Expand All @@ -222,7 +232,15 @@ def do_POST(self):

# Return updated labels
view_result = gh(
["issue", "view", issue_number, "--repo", allowed_repo, "--json", "labels"],
[
"issue",
"view",
issue_number,
"--repo",
allowed_repo,
"--json",
"labels",
],
token,
)
if view_result.returncode != 0:
Expand Down Expand Up @@ -265,7 +283,9 @@ def main() -> None:
import argparse

parser = argparse.ArgumentParser(description="REST server for GitHub operations")
parser.add_argument("--port", type=int, default=8081, help="HTTP port (default: 8081)")
parser.add_argument(
"--port", type=int, default=8081, help="HTTP port (default: 8081)"
)
args = parser.parse_args()

token = os.environ.get("GH_TOKEN")
Expand Down
Loading
Loading