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
6 changes: 4 additions & 2 deletions packages/runtime/src/band-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,10 @@ function buildBwrapArgs(
"--symlink", "usr/lib64", "/lib64",
"--ro-bind", "/etc", "/etc",
"--bind-try", "/run", "/run",
"--proc", "/proc",
"--dev", "/dev",
"--dir", "/dev",
"--dev-bind", "/dev/null", "/dev/null",
"--dev-bind", "/dev/zero", "/dev/zero",
"--dev-bind", "/dev/urandom", "/dev/urandom",
"--perms", "1777", "--tmpfs", "/tmp",
"--perms", "1777", "--tmpfs", "/home",
"--bind", workdir, workdir,
Expand Down
6 changes: 4 additions & 2 deletions packages/runtime/src/banded-skills/lima-exec-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ export function buildBwrapCommand(
"--ro-bind-try /etc/ssl /etc/ssl",
"--ro-bind-try /etc/ca-certificates /etc/ca-certificates",
"--ro-bind-try /etc/alternatives /etc/alternatives",
"--proc /proc",
"--dev /dev",
"--dir /dev",
"--dev-bind /dev/null /dev/null",
"--dev-bind /dev/zero /dev/zero",
"--dev-bind /dev/urandom /dev/urandom",
"--tmpfs /tmp",
"--tmpfs /home",
`--bind ${vmWorkdir} ${vmWorkdir}`,
Expand Down
10 changes: 7 additions & 3 deletions packages/runtime/test/unit/banded-skills/lima-exec-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ describe("buildBwrapCommand", () => {
expect(cmd).toContain("--ro-bind-try /etc/ca-certificates /etc/ca-certificates");
});

test("includes proc, dev, tmpfs mounts", () => {
test("restricts proc and dev mounts", () => {
const cmd = buildBwrapCommand("/work/abc");
expect(cmd).toContain("--proc /proc");
expect(cmd).toContain("--dev /dev");
expect(cmd).not.toContain("--proc /proc");
expect(cmd).not.toContain("--dev /dev");
expect(cmd).toContain("--dir /dev");
expect(cmd).toContain("--dev-bind /dev/null /dev/null");
expect(cmd).toContain("--dev-bind /dev/zero /dev/zero");
expect(cmd).toContain("--dev-bind /dev/urandom /dev/urandom");
expect(cmd).toContain("--tmpfs /tmp");
expect(cmd).toContain("--tmpfs /home");
});
Expand Down
17 changes: 12 additions & 5 deletions skills/github/scripts/resources/pr-merge/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@ fi

# gh pr merge outputs text, not JSON
STDERR_FILE=$(mktemp)
RESULT=$(gh pr merge "${ARGS[@]}" 2>"$STDERR_FILE") || {
MAX_ATTEMPTS=3
for ((attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)); do
RESULT=$(gh pr merge "${ARGS[@]}" 2>"$STDERR_FILE") && break
ERROR=$(cat "$STDERR_FILE")
rm -f "$STDERR_FILE"
echo "{\"error\": \"$ERROR\"}" > "${OUTPUT_PATH:-/dev/stdout}"
exit 1
}
if [[ "$ERROR" != *"Base branch was modified"* || "$attempt" -eq "$MAX_ATTEMPTS" ]]; then
rm -f "$STDERR_FILE"
echo "{\"error\": \"$ERROR\"}" > "${OUTPUT_PATH:-/dev/stdout}"
exit 1
fi
# Clear the previous error before retrying so only the next attempt is inspected.
truncate -s 0 "$STDERR_FILE"
sleep 2
done
rm -f "$STDERR_FILE"

echo "{\"merged\": true, \"message\": \"$RESULT\"}" > "${OUTPUT_PATH:-/dev/stdout}"
23 changes: 18 additions & 5 deletions skills/github/test/github-skill-issue-edit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
import { describe, expect, test, beforeAll } from "bun:test";
import { gh, GITHUB_REPO, TIMEOUT, pollIssueState } from "./github-helpers";

const MAX_VISIBILITY_ATTEMPTS = 5;
const RETRY_DELAY_MS = 1500;

async function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}

describe("github: issue edit & close/reopen", () => {
// ── Labels + assignees ──────────────────────────────────────────

Expand Down Expand Up @@ -37,11 +44,17 @@

test("view issue shows label and assignee", async () => {
expect(issueNumber).toBeDefined();
const result = await gh("issue-view", { repo: GITHUB_REPO!, number: issueNumber });
if (!result.success) throw new Error(`issue-view labels failed: ${result.error}`);
const data = result.data as any;
expect(data.labels.some((l: any) => l.name === labelName)).toBe(true);
expect(data.assignees.length).toBeGreaterThanOrEqual(1);
let latestIssueData: { labels: Array<{ name: string }>; assignees: unknown[] } | undefined;
for (let attempt = 0; attempt < MAX_VISIBILITY_ATTEMPTS; attempt++) {
const result = await gh("issue-view", { repo: GITHUB_REPO!, number: issueNumber });
if (!result.success) throw new Error(`issue-view labels failed: ${result.error}`);
latestIssueData = result.data as { labels: Array<{ name: string }>; assignees: unknown[] };
if (latestIssueData.labels.some((l) => l.name === labelName) && latestIssueData.assignees.length >= 1) break;
if (attempt < MAX_VISIBILITY_ATTEMPTS - 1) await sleep(RETRY_DELAY_MS);
}
if (!latestIssueData) throw new Error("issue-view did not return data");
expect(latestIssueData.labels.some((l) => l.name === labelName)).toBe(true);

Check failure on line 56 in skills/github/test/github-skill-issue-edit.test.ts

View workflow job for this annotation

GitHub Actions / Skill Tests (Direct)

error: expect(received).toBe(expected)

Expected: true Received: false at <anonymous> (/home/runner/work/bands/bands/skills/github/test/github-skill-issue-edit.test.ts:56:72)
expect(latestIssueData.assignees.length).toBeGreaterThanOrEqual(1);
}, TIMEOUT);

test("list issues filtered by assignee", async () => {
Expand Down
Loading