-
Notifications
You must be signed in to change notification settings - Fork 5
feat: 8 framework adapters + CI/CD + Demo + Docker #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
982c4d8
75eccbe
a0895c6
9272dd6
710c729
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| name: Adapters CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main, feat/*] | ||
| paths: | ||
| - 'adapters/**' | ||
| - '.github/workflows/adapters-ci.yml' | ||
| pull_request: | ||
| branches: [main] | ||
| paths: | ||
| - 'adapters/**' | ||
| - '.github/workflows/adapters-ci.yml' | ||
|
|
||
| jobs: | ||
| test-adapters: | ||
|
Comment on lines
+15
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '1,170p' .github/workflows/adapters-ci.yml | nl -ba
echo
echo "== diff stat/name only relevant workflow =="
git diff -- .github/workflows/adapters-ci.yml | sed -n '1,220p'
echo
echo "== permissions references in workflow =="
python3 - <<'PY'
from pathlib import Path
p=Path('.github/workflows/adapters-ci.yml')
for i,line in enumerate(p.read_text().splitlines(), 1):
if 'permissions:' in line or 'GITHUB_TOKEN' in line or 'packages:' in line:
print(f'{i}: {line}')
PYRepository: Das-rebel/a3m-router Length of output: 221 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '1,170p' .github/workflows/adapters-ci.yml | awk '{printf "%6d %s\n", NR, $0}'
echo
echo "== diff stat and relevant hunk =="
git diff -- .github/workflows/adapters-ci.yml | head -n 220 || true
echo
echo "== permissions/token/package references in workflow =="
python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/adapters-ci.yml')
for i, line in enumerate(p.read_text().splitlines(), 1):
if any(s in line for s in ('permissions:', 'GITHUB_TOKEN', 'packages:', 'ghcr.io', 'docker/login-action', 'docker/build-push-action')):
print(f'{i}: {line}')
PY
echo
echo "== jobs named docker-build and uses of packages permissions =="
python3 - <<'PY'
from pathlib import Path
text = Path('.github/workflows/adapters-ci.yml').read_text()
lines = text.splitlines()
for i, line in enumerate(lines, 1):
if line.rstrip() == 'docker-build:':
print(f'job docker-build starts around line {i}')
# Print context until next top-level key
for j in range(i, min(len(lines), i + 80)):
print(f'{j}: {lines[j-1]}')
if lines[j-1].startswith(' ') and not lines[j-1].strip().startswith('-') and lines[j-1][0] in ' \t':
# simple continuation until file end or next top-level (not indent under job?) keep until next top-level key
pass
break
PYRepository: Das-rebel/a3m-router Length of output: 5594 Set least-privilege token permissions. The workflow uses repository-default 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| runs-on: ubuntu-latest | ||
|
|
||
| strategy: | ||
| matrix: | ||
| python-version: ['3.9', '3.10', '3.11', '3.12'] | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Python ${{ matrix.python-version }} | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
|
|
||
| - name: Cache pip packages | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.cache/pip | ||
| key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('adapters/**/requirements*.txt') }} | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| cd adapters | ||
| pip install -e . | ||
| pip install pytest pytest-asyncio black isort flake8 | ||
|
|
||
| - name: Lint with black | ||
| run: | | ||
| cd adapters | ||
| black --check a3m_adapter/ --exclude='/(\.git|\.venv|__pycache__)/' | ||
|
|
||
| - name: Lint with isort | ||
| run: | | ||
| cd adapters | ||
| isort --check-only a3m_adapter/ --exclude='/(\.git|\.venv|__pycache__)/' | ||
|
|
||
| - name: Lint with flake8 | ||
| run: | | ||
| cd adapters | ||
| flake8 a3m_adapter/ --max-line-length=100 --exclude='/(\.git|\.venv|__pycache__)/' | ||
|
|
||
| - name: Run tests | ||
| run: | | ||
| cd adapters | ||
| pytest a3m_adapter/tests/ -v --tb=short | ||
|
|
||
| test-integration: | ||
| runs-on: ubuntu-latest | ||
| needs: test-adapters | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
|
|
||
| - name: Start A3M Router | ||
| run: | | ||
| npx a3m-router serve & | ||
| sleep 5 | ||
| curl -f http://localhost:8787/health || exit 1 | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: '3.11' | ||
|
|
||
| - name: Install adapter and test deps | ||
| run: | | ||
| cd adapters | ||
| pip install -e . | ||
| pip install requests pytest pytest-asyncio | ||
|
|
||
| - name: Run integration tests | ||
| run: | | ||
| cd adapters | ||
| pytest a3m_adapter/tests/ -v --tb=short -k "integration" | ||
|
|
||
| publish-adapters: | ||
| runs-on: ubuntu-latest | ||
| needs: test-integration | ||
| if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: '3.11' | ||
|
|
||
| - name: Publish to PyPI | ||
| env: | ||
| PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} | ||
| run: | | ||
| cd adapters | ||
| pip install build twine | ||
| python -m build | ||
| twine upload --token $PYPI_TOKEN dist/* | ||
|
|
||
| docker-build: | ||
| runs-on: ubuntu-latest | ||
| needs: test-integration | ||
| if: github.event_name == 'push' | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Build Docker image | ||
| run: | | ||
| docker build -t ghcr.io/das-rebel/a3m-router:latest . | ||
|
|
||
| - name: Run container health check | ||
| run: | | ||
| docker run -d --name a3m-test -p 8787:8787 ghcr.io/das-rebel/a3m-router:latest | ||
| sleep 5 | ||
| curl -f http://localhost:8787/health | ||
| docker stop a3m-test | ||
|
|
||
| - name: Push to GHCR | ||
| if: github.event_name == 'push' | ||
| run: | | ||
| echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin | ||
| docker push ghcr.io/das-rebel/a3m-router:latest | ||
|
Comment on lines
+119
to
+142
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files .github/workflows/adapters-ci.yml || true
if [ -f .github/workflows/adapters-ci.yml ]; then
echo "== workflow excerpt =="
sed -n '1,220p' .github/workflows/adapters-ci.yml | cat -n
fi
echo "== search branch filters and docker-push usage =="
rg -n "branches:|branches-ignore|paths-ignore|docker-build|docker push|ghcr.io/das-rebel/a3m-router|GITHUB_TOKEN|github.event_name|github.ref_name|github.ref" .github/workflows || trueRepository: Das-rebel/a3m-router Length of output: 6244 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
p = Path(".github/workflows/adapters-ci.yml")
text = p.read_text() if p.exists() else ""
print("== docker-build step names ==")
m = re.search(r'^ docker-build:(\n[ \t]+.*?)(?:\n [a-zA-Z0-9_-]+:|\Z)', text, re.S)
print(m.group(1) if m else "not found")
print("== condition on triggers containing 'push' ==")
for rexp in [
r'^on:\s*$\n((?:(?:[ \t]+[^\n]+)|(?:[ \t]+push:[^\n]*)|(?:(?:\n[ \t][ \t-]?(?:branches|branches-ignore|paths|paths-ignore):[^\n]*)|(?:[ \t]+(?:(?:[^\n])))*)+)*)',
r'^[ \t]*push:(.*?)(?=\n\n|\n [a-zA-Z0-9_-]+:|\Z)',
r'^[ \t]{2}branches:(.*?)(?=\n branches-ignore:|\n[ \t]{2}[a-zA-Z0-9_-]+:|\Z)',
]:
alls = re.findall(rexp, text, re.S | re.M)
if alls:
print(rexp[:60], "-", alls[:5])
print("== deterministic parse-ish indicators ==")
checks = {
"workflow_file_exists": p.exists(),
"push_trigger": bool(re.search(r'^ *push:', text, flags=re.M)),
"docker_push_exists": "docker push ghcr.io/das-rebel/a3m-router:latest" in text,
"login_exists": "docker login ghcr.io" in text,
"checks_main_or_all_branches": any(x in text for x in ["ghcr.io/das-rebel/a3m-router:latest", "latest", "branches:"] and not re.search(r"branches:\n[ \t]+- *refs/heads/[^\\n]*main|branches:\n[ \t]+- *[\*$]|\n\s*branches-ignore:", text)),
}
for k,v in checks.items():
print(f"{k}={v}")
PYRepository: Das-rebel/a3m-router Length of output: 641 Do not publish
Restrict the registry login and push steps to 🧰 Tools🪛 zizmor (1.29.0)[warning] 125-125: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [warning] 119-143: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block (excessive-permissions) [error] 141-141: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) 🤖 Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: Das-rebel/a3m-router
Length of output: 232
🏁 Script executed:
Repository: Das-rebel/a3m-router
Length of output: 232
🏁 Script executed:
Repository: Das-rebel/a3m-router
Length of output: 5132
Enable tag-triggered workflow runs.
push.branchesfilters out tag pushes, sopublish-adaptersnever reaches its tag condition and cannot publish a versioned release.Proposed fix
push: branches: [main, feat/*] + tags: ['v*']📝 Committable suggestion
🤖 Prompt for AI Agents