Skip to content
Open
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
20 changes: 18 additions & 2 deletions .github/scripts/check_approval_drift.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,15 @@ def audit_pr(
if not reviewed_head:
latest = approvals[-1]
reviewer = (latest.get("user") or {}).get("login", "?")
approved_on = _short(latest.get("commit_id"))
approved_sha = latest.get("commit_id")
approved_on = _short(approved_sha)
merged_head = _short(head_sha)
diff_link = _compare_link(repo, approved_sha, head_sha, merged_head)
return (
"changed-after-approval",
(
f"last approval by @{reviewer} was on {approved_on}, but merged "
f"head was {_short(head_sha)} — commits landed after review"
f"head was {diff_link} — commits landed after review"
),
)

Expand All @@ -139,6 +142,19 @@ def _short(sha: object) -> str:
return str(sha)[:9] if sha else "?"


def _compare_link(
repo: str, base: object, head: object, label: str
) -> str:
"""Markdown link to the GitHub compare page between *base* and *head*.

Falls back to plain text if either SHA is missing so the report never
breaks on a sparse API response.
"""
if not base or not head:
return label
return f"[{label}](https://github.com/{repo}/compare/{base}...{head})"


def main() -> int:
token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
repo = resolve_repo()
Expand Down
32 changes: 27 additions & 5 deletions .github/scripts/check_dependency_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,27 @@ def main() -> int:
if before[n]["version"] != after[n]["version"]
}

# First-party openhands-* packages are version-bumped on every release;
# exclude them from the external-dep count but still surface them below.
def _is_openhands(name: str) -> bool:
return name.lower().startswith("openhands-")

bumped_external = {
n: v for n, v in bumped.items() if not _is_openhands(n)
}
bumped_openhands = {
n: v for n, v in bumped.items() if _is_openhands(n)
}

report.add(f"Baseline: `{baseline}`")
report.add(
f"Added: **{len(added)}**, bumped: **{len(bumped)}**, "
f"Added: **{len(added)}**, bumped: **{len(bumped_external)}**, "
f"removed: **{len(removed)}**."
)
if bumped_openhands:
report.add(
f"_(plus {len(bumped_openhands)} internal `openhands-*` bump(s))_"
)
report.add("")

# --- non-registry sources on new/changed packages (supply-chain surface) --
Expand Down Expand Up @@ -199,11 +215,17 @@ def main() -> int:
for name in sorted(added):
report.add(f"- `{name}=={added[name]['version']}`")
report.add("\n</details>")
if bumped:
if bumped_external:
report.add("<details><summary>Bumped dependencies</summary>\n")
for name in sorted(bumped):
old, new = bumped[name]
report.add(f"- `{name}`: {old} → {new}")
for name in sorted(bumped_external):
old_v, new_v = bumped_external[name]
report.add(f"- `{name}`: {old_v} → {new_v}")
report.add("\n</details>")
if bumped_openhands:
report.add("<details><summary>Internal `openhands-*` bumps</summary>\n")
for name in sorted(bumped_openhands):
old_v, new_v = bumped_openhands[name]
report.add(f"- `{name}`: {old_v} → {new_v}")
report.add("\n</details>")

sys.stdout.write(report.render())
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/security_scan_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def warn(self, reason: str) -> None:

def render(self) -> str:
if self.blocking:
status = f"❌ {len(self.blocking)} blocking finding(s)"
status = f"❌ {len(self.blocking)} finding(s)"
elif self.warnings:
status = f"⚠️ {len(self.warnings)} warning(s), nothing blocking"
else:
Expand Down
Loading