Skip to content

Commit a458537

Browse files
Merge pull request #1 from codacy/feat/od-71
feat: update container to use correct skill OD-71
2 parents 1d7af8c + 067def8 commit a458537

8 files changed

Lines changed: 228 additions & 71 deletions

File tree

README.md

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ docker compose run --rm codacy-ai
88

99
Required env vars: `CODACY_API_TOKEN`, and `ANTHROPIC_API_KEY` or `GEMINI_API_KEY` (or both).
1010

11-
> **Docker Desktop users:** set Memory to at least 12 GB in Settings → Resources → Memory. Analysis peaks at ~10.5 GB.
11+
The repository at `SOURCE_PATH` must already be on Codacy Cloud with at least one finished analysis. The container tunes
12+
the cloud configuration via Cloud reanalysis — it does not run local analysis, and it does not import not-yet-on-Codacy
13+
repositories.
1214

1315
Or from any folder, without the compose file:
1416

1517
```bash
1618
docker run --rm -it \
1719
--cap-add=NET_ADMIN --cap-add=NET_RAW \
1820
--device /dev/kmsg:/dev/kmsg \
19-
--memory=12g --memory-swap=12g \
2021
-v codacy-tool-cache:/home/node/.codacy \
2122
-v $(pwd):/workspace \
2223
-e CODACY_API_TOKEN -e ANTHROPIC_API_KEY -e GEMINI_API_KEY \
@@ -29,35 +30,86 @@ Or with an explicit env file:
2930
docker run --rm -it \
3031
--cap-add=NET_ADMIN --cap-add=NET_RAW \
3132
--device /dev/kmsg:/dev/kmsg \
32-
--memory=12g --memory-swap=12g \
3333
-v codacy-tool-cache:/home/node/.codacy \
3434
-v $(pwd):/workspace \
35-
--env-file /path/to/.env \
35+
--env-file ./../.env \
3636
codacy/autoconfig
3737
```
3838

39-
| Flag | Purpose |
40-
|---|---|
41-
| `--rm` | Delete the container on exit |
42-
| `-it` | Interactive terminal |
43-
| `--cap-add=NET_ADMIN --cap-add=NET_RAW` | Required to enforce the outbound firewall inside the container |
44-
| `--device /dev/kmsg:/dev/kmsg` | Kernel device needed by the firewall setup |
45-
| `--memory=12g --memory-swap=12g` | Cap memory at 12 GB, no swap (analysis peaks ~10.5 GB) |
46-
| `-v codacy-tool-cache:/home/node/.codacy` | Persistent volume so downloaded tools survive between runs |
47-
| `-v $(pwd):/workspace` | Mounts your current folder as `/workspace` |
48-
| `-e ...` | Passes API tokens from your host environment into the container |
49-
| `--env-file /path/to/.env` | Alternative to `-e` flags — loads vars from a file |
39+
| Flag | Purpose |
40+
|-------------------------------------------|-----------------------------------------------------------------|
41+
| `--rm` | Delete the container on exit |
42+
| `-it` | Interactive terminal |
43+
| `--cap-add=NET_ADMIN --cap-add=NET_RAW` | Required to enforce the outbound firewall inside the container |
44+
| `--device /dev/kmsg:/dev/kmsg` | Kernel device needed by the firewall block-log stream |
45+
| `-v codacy-tool-cache:/home/node/.codacy` | Persistent volume so downloaded tools survive between runs |
46+
| `-v $(pwd):/workspace` | Mounts your current folder as `/workspace` |
47+
| `-e ...` | Passes API tokens from your host environment into the container |
48+
| `--env-file /path/to/.env` | Alternative to `-e` flags — loads vars from a file |
5049

5150
To rebuild the image:
5251

5352
```bash
5453
docker compose build
5554
```
5655

56+
## Two pipelines, local and server
57+
58+
The image ships two entrypoint scripts:
59+
60+
- `local-pipeline.sh` (default). For developers running the container against a mounted source folder. Used by
61+
`docker compose` and the `docker run` examples above. Invokes `/configure-codacy-cloud` against `/workspace`.
62+
- `server-pipeline.sh`. For the Active Analysis Manager (AAM) in production. Clones the repository via `GIT_TOKEN`,
63+
invokes `/configure-codacy-cloud`, and uploads a JSONL summary to a presigned S3 URL. The clone URL is built per
64+
provider (`CODACY_PROVIDER` of `gh`/`ghe` for GitHub, `gl`/`gle` for GitLab, `bb` for Bitbucket).
65+
66+
Both scripts run the same skill. The skill tunes a repository's Codacy Cloud configuration via Cloud reanalysis and
67+
never runs local static analysis tools — that's why the container's egress allowlist is narrow (Claude, Gemini, Codacy).
68+
69+
To test `server-pipeline.sh` locally, override the entrypoint and provide the additional env vars. Note that the
70+
local firewall does not allow git provider hosts, so set `RUNNING_IN_K8S=true` to skip it for this test:
71+
72+
```bash
73+
docker run --rm -it \
74+
-v codacy-tool-cache:/home/node/.codacy \
75+
-e RUNNING_IN_K8S=true \
76+
-e CODACY_API_TOKEN \
77+
-e ANTHROPIC_API_KEY \
78+
-e GIT_TOKEN \
79+
-e CODACY_PROVIDER=gh \
80+
-e CODACY_ORG_NAME=your-org \
81+
-e CODACY_REPO_NAME=your-repo \
82+
-e RESULT_UPLOAD_URL=https://httpbin.org/put \
83+
--entrypoint /usr/local/bin/server-pipeline.sh \
84+
codacy/autoconfig
85+
```
86+
87+
`httpbin.org/put` accepts any PUT and is useful for smoke-testing the upload step.
88+
89+
To capture the summary on your host instead of sending it to httpbin, run a tiny HTTP sink in another terminal:
90+
91+
```bash
92+
python3 -c "
93+
import http.server
94+
class H(http.server.BaseHTTPRequestHandler):
95+
def do_PUT(self):
96+
n = int(self.headers.get('Content-Length', 0))
97+
open('summary.received.jsonl', 'wb').write(self.rfile.read(n))
98+
self.send_response(200); self.end_headers()
99+
http.server.HTTPServer(('0.0.0.0', 8080), H).serve_forever()
100+
"
101+
```
102+
103+
Then point the container at it with `RESULT_UPLOAD_URL=http://host.docker.internal:8080/upload`.
104+
105+
Required env vars for the server pipeline: `CODACY_API_TOKEN`, `ANTHROPIC_API_KEY`, `GIT_TOKEN`, `CODACY_PROVIDER`,
106+
`CODACY_ORG_NAME`, `CODACY_REPO_NAME`, `RESULT_UPLOAD_URL`. The script fails fast if any are missing.
107+
57108
## What's inside
58109

59110
- `codacy` — Codacy Cloud CLI
60-
- `codacy-analysis`runs static analysis tools locally (trivy, ruff, opengrep, pmd, checkov, etc., downloaded on first use)
111+
- `codacy-analysis`Codacy Analysis CLI (used by the skill only for config-file operations)
61112
- `claude` / `gemini` — AI assistants
62113
- Java 21, Python 3.12, Ruby, Go 1.26, shellcheck
63-
- Outbound firewall — allowlist only (GitHub, Codacy, Anthropic, Google, npm, PyPI)
114+
- Outbound firewall — allowlist for Claude, Gemini, and Codacy only. In production (k8s) the firewall is skipped and
115+
egress is enforced by NetworkPolicy at the cluster level instead.

docker-compose.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ services:
77
cap_add:
88
- NET_ADMIN
99
- NET_RAW
10-
mem_limit: 12g
11-
memswap_limit: 12g
1210
devices:
1311
- /dev/kmsg:/dev/kmsg
1412
volumes:

docker/Dockerfile

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,17 @@ RUN npm install -g \
4242
@codacy/codacy-cloud-cli \
4343
@codacy/analysis-cli
4444

45-
# Firewall init — node user gets sudo rights for this script only
4645
# Pre-bake skills — Claude loads via --plugin-dir, Gemini installs from local path
46+
# ADD'ing the master ref content makes Docker invalidate this layer whenever codacy-skills master moves,
47+
# so a fresh `docker build` always gets the latest skills without --no-cache.
48+
ADD https://api.github.com/repos/codacy/codacy-skills/git/refs/heads/master /tmp/codacy-skills-ref
4749
RUN git clone --depth 1 https://github.com/codacy/codacy-skills.git /opt/codacy-skills
4850

4951
COPY docker/init-firewall.sh /usr/local/bin/init-firewall.sh
5052
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
51-
COPY docker/pipeline.sh /usr/local/bin/pipeline.sh
52-
RUN chmod +x /usr/local/bin/init-firewall.sh /usr/local/bin/entrypoint.sh /usr/local/bin/pipeline.sh \
53+
COPY docker/local-pipeline.sh /usr/local/bin/local-pipeline.sh
54+
COPY docker/server-pipeline.sh /usr/local/bin/server-pipeline.sh
55+
RUN chmod +x /usr/local/bin/init-firewall.sh /usr/local/bin/entrypoint.sh /usr/local/bin/local-pipeline.sh /usr/local/bin/server-pipeline.sh \
5356
&& printf 'node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh\nnode ALL=(root) NOPASSWD: /bin/chown -R node\\:node /home/node/.codacy\n' \
5457
> /etc/sudoers.d/node-firewall \
5558
&& chmod 0440 /etc/sudoers.d/node-firewall
@@ -61,11 +64,12 @@ USER node
6164
COPY --chown=node:node docker/claude-settings.json /home/node/.claude/settings.json
6265
RUN mkdir -p /home/node/.claude/commands/references \
6366
&& cp /opt/codacy-skills/skills/configure-codacy/SKILL.md /home/node/.claude/commands/configure-codacy.md \
67+
&& cp /opt/codacy-skills/skills/configure-codacy-cloud/SKILL.md /home/node/.claude/commands/configure-codacy-cloud.md \
6468
&& cp /opt/codacy-skills/skills/codacy-analysis-cli/SKILL.md /home/node/.claude/commands/codacy-analysis-cli.md \
6569
&& cp /opt/codacy-skills/skills/codacy-cloud-cli/SKILL.md /home/node/.claude/commands/codacy-cloud-cli.md \
6670
&& cp /opt/codacy-skills/skills/codacy-analysis-cli/references/* /home/node/.claude/commands/references/
6771

6872
WORKDIR /workspace
6973

7074
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
71-
CMD ["pipeline.sh"]
75+
CMD ["local-pipeline.sh"]

docker/entrypoint.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
#!/bin/bash
22
set -e
33

4-
sudo /usr/local/bin/init-firewall.sh
4+
# In k8s, egress is controlled by NetworkPolicy; the in-container iptables firewall
5+
# requires NET_ADMIN and is not available. Skip it when RUNNING_IN_K8S is set.
6+
if [ -z "${RUNNING_IN_K8S:-}" ]; then
7+
sudo /usr/local/bin/init-firewall.sh
8+
fi
59

610
# Fix ownership of the tool-cache volume (mounted as root by Docker)
711
sudo chown -R node:node /home/node/.codacy 2>/dev/null || true

docker/init-firewall.sh

100755100644
Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
#!/bin/bash
2+
# Minimal egress allowlist for the container. Three categories only.
3+
# - Claude (api.anthropic.com, statsig.anthropic.com)
4+
# - Gemini (generativelanguage.googleapis.com, oauth2.googleapis.com)
5+
# - Codacy API (api.codacy.com, app.codacy.com)
6+
# Designed for the configure-codacy-cloud flow which makes no local analysis calls.
7+
# To test server-pipeline.sh locally (which needs git clone egress), set RUNNING_IN_K8S=true
8+
# to skip this firewall and rely on the developer's host firewall instead.
9+
210
set -euo pipefail
311
IFS=$'\n\t'
412

@@ -21,43 +29,22 @@ if [ -n "$DOCKER_DNS_RULES" ]; then
2129
echo "$DOCKER_DNS_RULES" | xargs -L 1 iptables -t nat
2230
fi
2331

24-
# Protocol-level rules (set before the default-DROP policy)
32+
# Protocol-level rules
2533
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
2634
iptables -A INPUT -p udp --sport 53 -j ACCEPT
27-
iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
28-
iptables -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
2935
iptables -A INPUT -i lo -j ACCEPT
3036
iptables -A OUTPUT -o lo -j ACCEPT
3137

3238
# Build the allowlist
3339
ipset create allowed-domains hash:net
3440

35-
# GitHub IP ranges — covers api.github.com, github.com, raw content, AND ghcr.io (packages)
36-
# ghcr.io (Trivy vulnerability DB) lives under the packages CIDR block
37-
gh_ranges=$(curl -s https://api.github.com/meta)
38-
while read -r cidr; do
39-
ipset add allowed-domains "$cidr" 2>/dev/null || true
40-
done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git + .packages)[]' | aggregate -q)
41-
42-
# Resolve each domain to IPs at startup and add to the allowlist
4341
for domain in \
44-
"registry.npmjs.org" \
4542
"api.anthropic.com" \
4643
"statsig.anthropic.com" \
47-
"statsig.com" \
48-
"sentry.io" \
49-
"app.codacy.com" \
50-
"api.codacy.com" \
5144
"generativelanguage.googleapis.com" \
5245
"oauth2.googleapis.com" \
53-
"cveawg.mitre.org" \
54-
"api.osv.dev" \
55-
"pypi.org" \
56-
"files.pythonhosted.org" \
57-
"pkg-containers.githubusercontent.com" \
58-
"bc-api.bridgecrew.io" \
59-
"bc-api.prismacloud.io" \
60-
"cdn.prismacloud.io"; do
46+
"api.codacy.com" \
47+
"app.codacy.com"; do
6148
for _ in 1 2 3 4 5; do
6249
ips=$(dig +noall +answer A "$domain" | awk '$4 == "A" { print $5 }')
6350
while read -r ip; do
@@ -92,11 +79,10 @@ iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited
9279

9380
# Sanity checks
9481
curl --connect-timeout 5 https://example.com >/dev/null 2>&1 && { echo "FIREWALL ERROR: example.com should be blocked"; exit 1; }
95-
curl --connect-timeout 5 https://api.github.com/zen >/dev/null 2>&1 || { echo "FIREWALL ERROR: api.github.com should be reachable"; exit 1; }
9682
curl --connect-timeout 5 https://api.anthropic.com >/dev/null 2>&1 || true # 401 is fine, blocked is not
9783
curl --connect-timeout 5 https://app.codacy.com >/dev/null 2>&1 || { echo "FIREWALL ERROR: app.codacy.com should be reachable"; exit 1; }
9884

99-
echo "Firewall initialized."
85+
echo "Firewall initialized (claude + gemini + codacy)."
10086

10187
# Emit blocked outbound connections to stderr in real time.
10288
# /dev/kmsg must be mapped into the container: --device /dev/kmsg:/dev/kmsg

docker/local-pipeline.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
# Local pipeline: tunes an already-on-Codacy repository's cloud config from a mounted source folder.
3+
# Runs the /configure-codacy-cloud skill, which uses Codacy Cloud reanalysis (no local analysis tools).
4+
# Requirement: the repo at /workspace must already be on Codacy with at least one finished analysis.
5+
set -e
6+
7+
cd /workspace
8+
9+
if [ -n "${ANTHROPIC_API_KEY:-}" ]; then
10+
echo "==> Running configure-codacy-cloud with Claude..."
11+
claude -p "/configure-codacy-cloud" \
12+
--output-format stream-json \
13+
--verbose \
14+
--include-partial-messages \
15+
| jq --unbuffered -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
16+
17+
elif [ -n "${GEMINI_API_KEY:-}" ]; then
18+
echo "==> Running configure-codacy-cloud with Gemini..."
19+
echo "/configure-codacy-cloud" | gemini
20+
21+
else
22+
echo "Error: neither ANTHROPIC_API_KEY nor GEMINI_API_KEY is set." >&2
23+
exit 1
24+
fi

docker/pipeline.sh

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)