Skip to content
Merged
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
80 changes: 80 additions & 0 deletions .github/workflows/build-thailand.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Build and Push (Thailand)

# Builds the Thai-government sandbox image: the default agent-sandbox plus the
# Thailand-only skills (Dockerfile.thailand overlays `skills-thailand/`). It runs
# AFTER the default "Build and Push" workflow succeeds so the base image it
# overlays already exists, and pins the base to that same commit's `sha-` tag.
# This keeps the Thai skill out of the default image while shipping it in a
# separate, optional image.

on:
workflow_run:
workflows: ["Build and Push"]
types: [completed]
branches: [main]
workflow_dispatch:
inputs:
base_tag:
description: "Default agent-sandbox tag to overlay (e.g. latest, 0.3.0, sha-abc1234)"
default: latest

env:
REGISTRY: ghcr.io
# Separate image name: <owner>/agent-sandbox-thailand.
IMAGE_NAME: ${{ github.repository }}-thailand
BASE_IMAGE_NAME: eternisai/agent-sandbox

jobs:
build:
# workflow_run: only proceed if the base build succeeded. workflow_dispatch
# always proceeds.
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat .github/workflows/build-thailand.yml

Repository: EternisAI/agent-sandbox

Length of output: 2772


🌐 Web query:

GitHub Actions pinning commit SHA security best practices 2024

💡 Result:

As of June 2026, pinning GitHub Actions to a full-length commit SHA is considered the industry standard and a critical security best practice for mitigating supply chain risks [1][2][3]. ### Why Pinning to a Full-Length SHA is Essential * Immutability: Tags (e.g., @v4) and branches (e.g., @main) are mutable, meaning they can be updated or re-pointed to different commits by maintainers or malicious actors at any time [4][5][6]. Pinning to a full-length (40-character) commit SHA ensures that your workflow consistently runs the exact same code, providing a cryptographically secure, immutable reference [1][2][7]. * Mitigating Compromise: If an action's repository is compromised, attackers often attempt to inject malicious code into existing tags [8][2][3]. Because commit SHAs are immutable and content-addressed, a pinned SHA remains unaffected by such updates, preventing automatic execution of compromised code [4][2][9]. * Security Policies: GitHub now provides organization and repository-level policies that allow administrators to mandate SHA pinning [8][5][2]. When enabled, any workflow attempting to use a non-pinned action will fail, ensuring compliance across an entire organization [8][5]. ### Best Practices for Implementation * Use Full 40-Character SHAs: Never use shortened SHAs, as they carry a risk of collision and ambiguity [7]. Always use the full 40-character hexadecimal string [6][7]. * Maintain Human Readability: To preserve context, append the version tag as a comment in your workflow file [2][3]. This helps maintainers understand which version is being used while keeping the reference immutable [2][6]. * Example: uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 [2] * Automate Updates: Pinning manually creates maintenance overhead. Use dependency management tools like Dependabot or Renovate to automatically open pull requests that update your pinned SHAs when new releases are published [5][2][3]. * Audit Regularly: Use tools like Zizmor, Scorecards, or custom scripts to periodically scan your repositories for unpinned actions or short SHAs to ensure ongoing compliance with your security policies [2][10][3]. ### Recommended Workflow for Maintainers If you maintain your own GitHub Actions, you should also pin your internal (sub-action) dependencies to full commit SHAs [5]. This prevents your action from breaking when users adopt organization-wide SHA-enforcement policies [5].

Citations:


Pin GitHub Actions to full commit SHAs.

Lines 38, 43, 45, 61, and 69 reference actions by floating tags (@v*), which is a supply-chain risk. Pin each uses: to an immutable full 40-character commit SHA, optionally with the version tag as a comment for readability.

Suggested fix pattern
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@<full-commit-sha> # v4

-      - uses: docker/setup-buildx-action@v3
+      - uses: docker/setup-buildx-action@<full-commit-sha> # v3

-      - uses: docker/login-action@v3
+      - uses: docker/login-action@<full-commit-sha> # v3

-      - uses: docker/metadata-action@v5
+      - uses: docker/metadata-action@<full-commit-sha> # v5

-      - uses: docker/build-push-action@v5
+      - uses: docker/build-push-action@<full-commit-sha> # v5

Consider automating updates with Dependabot or Renovate.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 38-41: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 38-38: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-thailand.yml at line 38, Replace all floating
version tags in the uses directives with full 40-character commit SHAs for
security. For each GitHub Action reference currently using `@v`* format (such as
actions/checkout@v4, and others mentioned in the comment), pin them to their
corresponding immutable commit SHA. You may optionally include the version tag
as a comment after the SHA for readability. This applies to all uses directives
throughout the workflow file that reference actions by floating tags.

Source: Linters/SAST tools

with:
# Build from the same commit the base image was built from.
ref: ${{ github.event.workflow_run.head_sha || github.ref }}

- uses: docker/setup-buildx-action@v3

- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Resolve base image tag
id: base
run: |
if [ "${{ github.event_name }}" = "workflow_run" ]; then
short="$(git rev-parse --short=7 '${{ github.event.workflow_run.head_sha }}')"
echo "ref=sha-${short}" >> "$GITHUB_OUTPUT"
else
echo "ref=${{ inputs.base_tag }}" >> "$GITHUB_OUTPUT"
fi

- uses: docker/metadata-action@v5
id: meta
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha

- uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile.thailand
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64
build-args: |
BASE_IMAGE=${{ env.REGISTRY }}/${{ env.BASE_IMAGE_NAME }}:${{ steps.base.outputs.ref }}
cache-from: type=gha
cache-to: type=gha,mode=max
31 changes: 31 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,37 @@ docker buildx build --platform linux/amd64 -t ghcr.io/eternisai/agent-sandbox:<v

After pushing, update the tag in `backend-go/application.yaml` in the `axionhypothesis` repo.

## Skills

Skills live in `skills/<name>/SKILL.md` and are copied into every image at
`/home/sandbox/.agents/skills/`. The OpenCode runtime auto-discovers them; the
`description` frontmatter drives selection.

**Per-customer skills are kept out of the default image.** Customer-specific
skills live in a sibling `skills-<customer>/` dir (NOT `skills/`) and are layered
on only by that customer's overlay image — see the Thai-government image below.

## Thai-government image

`ghcr.io/eternisai/agent-sandbox-thailand` is the default image **plus** the
Thailand-only skills in `skills-thailand/` (today: `thai-government-data`,
covering the data.go.th and Parliament CKAN portals). It is a thin overlay built
from `Dockerfile.thailand`, which `FROM`s the default image and copies
`skills-thailand/` on top — so the two never drift and the Thai skills ship in
this image only.

```bash
docker build -f Dockerfile.thailand \
--build-arg BASE_IMAGE=ghcr.io/eternisai/agent-sandbox:<tag> \
-t ghcr.io/eternisai/agent-sandbox-thailand:<tag> .
```

CI: `.github/workflows/build-thailand.yml` runs after the default "Build and
Push" workflow succeeds and overlays that same commit's base image. At runtime
the Thai sandbox must inject `THAI_DATA_PROXY_URL` (the Thai egress proxy
endpoint, with creds) so `thai-government-data` can reach the geo-blocked
`.go.th` portals.

## Versioning

- Always use versioned tags (e.g. `0.3.0`), never `:latest`
Expand Down
30 changes: 30 additions & 0 deletions Dockerfile.thailand
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Thai-government agent-sandbox image.
#
# This is the default agent-sandbox image plus the Thailand-only skills (today:
# `thai-government-data`, covering the data.go.th and Parliament CKAN portals).
# It is built as a THIN OVERLAY on the published
# default image so the two never drift — the only delta is one extra skills dir.
# The Thailand skills deliberately live in `skills-thailand/` (NOT `skills/`), so
# the default image's `COPY skills/ ...` never picks them up and they ship ONLY
# in this image.
#
# Build locally:
# docker build -f Dockerfile.thailand \
# --build-arg BASE_IMAGE=ghcr.io/eternisai/agent-sandbox:<tag> \
# -t ghcr.io/<owner>/agent-sandbox-thailand:<tag> .
#
# At runtime the Thai sandbox must inject THAI_DATA_PROXY_URL (the Thai egress
# proxy endpoint, with creds) so the thai-government-data skill can reach the
# geo-blocked .go.th portals.

ARG BASE_IMAGE=ghcr.io/eternisai/agent-sandbox:latest
FROM ${BASE_IMAGE}
Comment on lines +20 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine Dockerfile.thailand
fd -t f "Dockerfile.thailand" --exec cat -n {} \;

Repository: EternisAI/agent-sandbox

Length of output: 1704


Avoid mutable :latest for BASE_IMAGE default.

Line 20 uses :latest, which makes local/manual builds non-reproducible and can drift from the intended base. Use an explicit immutable tag (or require the build arg).

Suggested fix
-ARG BASE_IMAGE=ghcr.io/eternisai/agent-sandbox:latest
+ARG BASE_IMAGE
 FROM ${BASE_IMAGE}

As per coding guidelines, Dockerfile* must use versioned tags and never :latest for Docker images.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ARG BASE_IMAGE=ghcr.io/eternisai/agent-sandbox:latest
FROM ${BASE_IMAGE}
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile.thailand` around lines 20 - 21, The BASE_IMAGE default value in
the ARG declaration uses the mutable :latest tag, which compromises
reproducibility of Docker builds. Replace the :latest tag with a specific,
immutable version tag (e.g., :v1.0.0 or a specific SHA digest) in the BASE_IMAGE
default argument to ensure consistent, reproducible builds across all
environments.

Source: Coding guidelines


# Overlay the Thailand-only skills into the same dir the OpenCode runtime scans.
COPY --chown=sandbox:sandbox skills-thailand/ /home/sandbox/.agents/skills/

# Mirror the base image's executable-bit fixup for any helper scripts the
# overlay ships (no-op today; the datagoth skill is SKILL.md-only).
RUN find /home/sandbox/.agents/skills -name "*.sh" -o -name "*.py" | xargs -r chmod +x

# USER, WORKDIR, EXPOSE, and ENTRYPOINT are inherited unchanged from the base.
Loading
Loading