Compare commits

..

11 Commits

Author SHA1 Message Date
293c44603e fix(ci): remove container directive from Gitea workflows for host-mode runner
All checks were successful
Forge CI / smoke-and-build (pull_request) Successful in 49s
The bezalel-vps-runner is registered in host mode (:host labels)
and cannot execute Docker containers. The container pinning added
in #180 causes all Gitea CI jobs to fail immediately with:

  Cannot connect to the Docker daemon at unix:///var/run/docker.sock

Remove container: from .gitea/workflows/*.yml while keeping it in
.github/workflows/ for actual GitHub Actions runners.

Fixes CI for all open PRs and main branch pushes.
2026-04-07 13:53:42 +00:00
e07c3bcf00 Merge pull request '[BEZALEL][Epic-001] The Forge CI Pipeline + Health Check Fix' (#175) from bezalel/epic-001-forge-ci into main
Some checks failed
Forge CI / smoke-and-build (push) Failing after 0s
2026-04-07 12:37:31 +00:00
fcdbdd9f50 Merge pull request '[BEZALEL][CI] Enable uv caching in Forge CI workflow' (#187) from bezalel/ci-uv-cache into main
Some checks failed
Forge CI / smoke-and-build (push) Failing after 0s
2026-04-07 12:37:27 +00:00
87209a933f Merge pull request '[claude] Fix CI runner: pin act-22.04 container for Node.js (#174)' (#180) from claude/issue-174 into main
Some checks failed
Forge CI / smoke-and-build (push) Failing after 0s
2026-04-07 12:37:06 +00:00
61d137798e Merge pull request '[BEZALEL] Fix syntax error breaking all CI (test_skill_name_traversal.py)' (#188) from bezalel/fix-indentation-error into main
Some checks failed
Forge CI / smoke-and-build (push) Has been cancelled
2026-04-07 12:36:49 +00:00
5009f972c1 fix: indentation error in test_skill_name_traversal.py line 282
All checks were successful
Forge CI / smoke-and-build (pull_request) Successful in 1m46s
2026-04-07 12:34:17 +00:00
0438120402 [BEZALEL][CI] Enable uv caching in Forge CI workflow
Some checks failed
Forge CI / smoke-and-build (pull_request) Failing after 41s
2026-04-07 12:27:59 +00:00
b580ed71bf [BEZALEL] Create skill: Gitea PR & Issue Workflow Automation (#181)
Some checks failed
Forge CI / smoke-and-build (push) Failing after 2s
2026-04-07 06:28:37 +00:00
Alexander Whitestone
8abd0ac01e fix(ci): pin container image with Node.js for act runner compatibility
Some checks failed
Forge CI / smoke-and-build (pull_request) Failing after 1s
The bezalel-vps-runner (act v0.2.11) fails in 1-6s because Node.js is
not in PATH of the default runner container, preventing any GitHub
Actions (actions/checkout, setup-uv, setup-node, etc.) from executing.

Add `container: catthehacker/ubuntu:act-22.04` to all workflow jobs.
This image is purpose-built for act runners and includes Node.js, git,
Python, npm, and other common CI tooling needed to run GitHub Actions.

Fixes #174

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 02:25:33 -04:00
3fc47a0e2e [claw-code] [CONFIG] Add Kimi model to fallback chain for Allegro and Bezalel (#151) (#177)
Some checks failed
Forge CI / smoke-and-build (push) Failing after 2s
Co-authored-by: claw-code <claw-code@timmy.local>
Co-committed-by: claw-code <claw-code@timmy.local>
2026-04-07 04:14:19 +00:00
cbe1b79fbb fix(forge_health_check): exclude caches/venvs and false-positive file types
Some checks failed
Forge CI / smoke-and-build (pull_request) Failing after 3s
- Add EXCLUDED_PATH_SEGMENTS to skip .cache, __pycache__, .venv, venv,
  site-packages, node_modules, .git, .tox
- Exclude .css files and secret_scan tooling from sensitive-file scan
- Reduces noise from 13,449 false positives to 3 real findings
2026-04-07 03:40:28 +00:00
10 changed files with 132 additions and 1 deletions

View File

@@ -20,6 +20,9 @@ jobs:
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Set up Python 3.11
run: uv python install 3.11

View File

@@ -19,6 +19,7 @@ jobs:
audit:
name: Audit Python dependencies
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-22.04
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5

View File

@@ -10,6 +10,7 @@ on:
jobs:
docs-site-checks:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-22.04
steps:
- uses: actions/checkout@v4

View File

@@ -19,6 +19,7 @@ jobs:
create-audit-issue:
name: Create quarterly security audit issue
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-22.04
steps:
- uses: actions/checkout@v4

View File

@@ -12,6 +12,7 @@ jobs:
scan:
name: Scan for secrets
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-22.04
steps:
- uses: actions/checkout@v4
with:

View File

@@ -12,6 +12,7 @@ jobs:
scan:
name: Scan PR for supply chain risks
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-22.04
steps:
- name: Checkout
uses: actions/checkout@v4

View File

@@ -14,6 +14,7 @@ concurrency:
jobs:
test:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-22.04
timeout-minutes: 10
steps:
- name: Checkout code

View File

@@ -98,9 +98,23 @@ class HealthReport:
self.passed = False
EXCLUDED_PATH_SEGMENTS = frozenset({
".cache", "__pycache__", ".venv", "venv", "site-packages",
".local/share/uv", "node_modules", ".git", ".tox",
})
def _is_excluded_path(path: Path) -> bool:
"""Skip cache, venv, and package-manager directories."""
parts = set(path.parts)
return not parts.isdisjoint(EXCLUDED_PATH_SEGMENTS)
def scan_orphaned_bytecode(root: Path, report: HealthReport) -> None:
"""Detect .pyc files without corresponding .py source files."""
for pyc in root.rglob("*.pyc"):
if _is_excluded_path(pyc):
continue
py = pyc.with_suffix(".py")
if not py.exists():
# Also check __pycache__ naming convention
@@ -142,6 +156,12 @@ def _is_sensitive_filename(name: str) -> bool:
lower = name.lower()
if lower == ".env.example":
return False
# Skip stylesheet and documentation artifacts
if lower.endswith(".css"):
return False
# Skip scanner tooling — these are detectors, not secrets
if lower in {"secret_scan.py", "secret_scanner.py"}:
return False
if any(pat in lower for pat in SENSITIVE_FILE_PATTERNS):
return True
if any(lower.startswith(pref) for pref in SENSITIVE_NAME_PREFIXES):
@@ -156,6 +176,8 @@ def scan_sensitive_file_permissions(root: Path, report: HealthReport, fix: bool
for fpath in root.rglob("*"):
if not fpath.is_file():
continue
if _is_excluded_path(fpath):
continue
# Skip test files — real secrets should never live in tests/
if "/tests/" in str(fpath) or str(fpath).startswith(str(root / "tests")):
continue

View File

@@ -0,0 +1,100 @@
---
name: gitea-workflow-automation
title: Gitea Workflow Automation
description: Automate Gitea issues, PRs, and repository workflows via the API for forge CI and backlog tracking.
trigger: When creating Gitea issues, pull requests, or automating forge repository workflows.
---
# Gitea Workflow Automation
## Trigger
Use this skill when automating Gitea operations: creating issues, opening PRs, checking repository state, or integrating Gitea into CI/backlog workflows.
## Prerequisites
- `GITEA_URL` environment variable set (e.g., `https://forge.alexanderwhitestone.com`)
- `GITEA_TOKEN` environment variable with a valid API token
- `GITEA_USER` or explicit owner/org name
- `curl` and `jq` available in the environment
## Step-by-Step Workflow
### 1. Verify Environment
```bash
: "${GITEA_URL?}" "${GITEA_TOKEN?}" "${GITEA_USER?}"
echo "Gitea env OK"
```
### 2. List Issues in a Repository
```bash
curl -s -H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}/issues?state=open&limit=50" | jq '.[] | {number, title, state}'
```
### 3. Create an Issue
```bash
curl -s -X POST -H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}/issues" \
-d "{\"title\":\"${TITLE}\",\"body\":\"${BODY}\",\"assignees\":[\"${ASSIGNEE}\"]}
```
- Escape newlines in `BODY` if passing inline; prefer a JSON file for multi-line bodies.
### 4. Create a Pull Request
```bash
curl -s -X POST -H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}/pulls" \
-d "{\"title\":\"${TITLE}\",\"body\":\"${BODY}\",\"head\":\"${BRANCH}\",\"base\":\"${BASE_BRANCH}\"}"
```
### 5. Check PR Status / Diff
```bash
curl -s -H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_NUMBER}" | jq '{number, title, state, mergeable}'
```
### 6. Push Code Before Opening PR
```bash
git checkout -b "${BRANCH}"
git add .
git commit -m "${COMMIT_MSG}"
git push origin "${BRANCH}"
```
### 7. Add Comments to Issues/PRs
```bash
curl -s -X POST -H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}/issues/${NUMBER}/comments" \
-d "{\"body\":\"${COMMENT_BODY}\"}"
```
## Verification Checklist
- [ ] Environment variables are exported and non-empty
- [ ] API responses are parsed with `jq` to confirm success
- [ ] Issue/PR numbers are captured from the JSON response for cross-linking
- [ ] Branch exists on remote before creating a PR
- [ ] Multi-line bodies are written to a temp JSON file to avoid escaping hell
## Pitfalls
- **Trailing slashes in `GITEA_URL`:** Ensure `GITEA_URL` does not end with `/` or double slashes break URLs.
- **Branch not pushed:** Creating a PR for a local-only branch returns 422.
- **Escape hell:** For multi-line issue/PR bodies, write JSON to a file with `cat <<EOF > /tmp/payload.json` and pass `@/tmp/payload.json` to curl instead of inline strings.
- **Token scope:** If operations fail with 403, verify the token has `repo` or `write:issue` scope.
- **Pagination:** Default limit is 30 issues; use `?limit=100` or paginate with `page=` for large backlogs.
## Example: Full Issue Creation with File Body
```bash
cat <<'EOF' > /tmp/issue.json
{
"title": "[Bezalel] Forge Health Check",
"body": "Build a diagnostic scanner for artifact integrity and permissions.\n\n- Detect .pyc without .py source\n- Detect world-readable sensitive files\n- Output JSON for CI consumption",
"assignees": ["bezalel"],
"labels": ["enhancement", "security"]
}
EOF
curl -s -X POST -H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${GITEA_URL}/api/v1/repos/Timmy_Foundation/hermes-agent/issues" \
-d @/tmp/issue.json | jq '.number'
```

View File

@@ -279,7 +279,7 @@ class TestSkillViewFilePathSecurity:
"""Tests for file_path parameter security in skill_view."""
@pytest.fixture
def setup_skill_with_files(self, tmp_path):
def setup_skill_with_files(self, tmp_path):
"""Create a skill with supporting files."""
skills_dir = tmp_path / "skills"
skills_dir.mkdir()