Skip to content

feat(ci): publish Argus app image and chart 0.1.1 - #13

Merged
mushrafmim merged 5 commits into
mainfrom
feat/ghcr-app-image
Sep 2, 2026
Merged

feat(ci): publish Argus app image and chart 0.1.1#13
mushrafmim merged 5 commits into
mainfrom
feat/ghcr-app-image

Conversation

@ginaxu1

@ginaxu1 ginaxu1 commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add a GitHub Actions workflow that builds and pushes the Argus application image to ghcr.io/lsflk/argus (:latest and :<git sha> on main).
  • Bump the Helm chart to 0.1.1 so the default image is ghcr.io/lsflk/argus:latest instead of the unpublished ghcr.io/opennsw/argus:<sha> that caused ImagePullBackOff.
  • After a successful image push on main, republish the stable chart to oci://ghcr.io/lsflk/charts/argus:0.1.1.

Test plan

  • Confirm Helm Chart CI lints and templates ghcr.io/lsflk/argus:latest
  • Confirm the PR image job builds (no push)
  • After merge, confirm ghcr.io/lsflk/argus:latest and ghcr.io/lsflk/argus:<sha> exist on GHCR
  • After merge, confirm helm pull oci://ghcr.io/lsflk/charts/argus --version 0.1.1 succeeds
  • If the new argus package is private, set visibility to public under https://github.com/orgs/LSFLK/packages
  • Notify teams to install chart 0.1.1 (do not use 0.1.0)

Chart 0.1.0 defaulted to an unpublished ghcr.io/opennsw/argus tag, which
left installs in ImagePullBackOff. Build and push ghcr.io/lsflk/argus on
main, then republish the chart so the default image is pullable.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ginaxu1
ginaxu1 requested a review from mushrafmim September 2, 2026 04:05
Drop the duplicate chart publisher, PR docker build, and unused Helm
image helper. Stable chart 0.1.1 still goes out through the existing
build-dev-chart dispatch.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ginaxu1
ginaxu1 force-pushed the feat/ghcr-app-image branch from ea097e9 to f507bc3 Compare September 2, 2026 04:55

@mushrafmim mushrafmim left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR Review & Feedback

Overall, the changes look solid and directly resolve the ImagePullBackOff issue by bumping the chart to 0.1.1 and pointing to ghcr.io/lsflk/argus:latest. Local verification (helm lint, helm template, docker build, unit tests) all pass cleanly.

A few recommendations and notes before merging:


1. ⚠️ Re-add PR Validation for Container Image

In commit ea097e9, pull_request trigger was removed from .github/workflows/build-image.yml.

  • Issue: PRs touching Go code, dependencies, or Dockerfile won't verify whether the container image builds until after merging to main.
  • Suggestion: Add back pull_request on main with paths for the code and Dockerfile, and keep push conditional:
    on:
      push:
        branches: [ main ]
        paths: ...
      pull_request:
        branches: [ main ]
        paths:
          - 'Dockerfile'
          - 'go.mod'
          - 'go.sum'
          - 'cmd/**'
          - 'internal/**'
          - 'pkg/**'
          - 'configs/**'
          - '.github/workflows/build-image.yml'
      workflow_dispatch:
    And make registry login / push conditional on event type:
        - name: Log in to GitHub Container Registry
          if: github.event_name != 'pull_request'
          uses: docker/login-action@v3
          ...
        - name: Build and push
          uses: docker/build-push-action@v6
          with:
            push: ${{ github.event_name != 'pull_request' }}

2. ⚠️ Kubernetes Caching: pullPolicy: IfNotPresent with tag: latest

In deployments/helm/argus/values.yaml:

image:
  repository: ghcr.io/lsflk/argus
  tag: latest
  pullPolicy: IfNotPresent
  • Issue: Because latest is mutable, nodes that already have a cached copy of latest will not pull newly published images under IfNotPresent.
  • Suggestion: Consider defaulting pullPolicy: Always when tag: latest, or encourage pinning specific tags (e.g. <git-sha> or 1.0.0) in production.

3. ℹ️ Helm Chart 0.1.1 Publishing Steps

With chart publishing kept separate from build-image.yml:

  • Merging to main will publish the image (:latest and :<sha>) and trigger build-dev-chart.yml (0.0.0-dev.<run_number>).
  • To publish the official 0.1.1 chart to oci://ghcr.io/lsflk/charts/argus:0.1.1, remember to dispatch build-dev-chart.yml with version: 0.1.1 after the image push completes.

4. ℹ️ GHCR Package Visibility

  • As noted in the test plan, please ensure an org admin sets the newly created ghcr.io/lsflk/argus package visibility to Public under https://github.com/orgs/LSFLK/packages so it can be pulled without imagePullSecrets.

5. 💡 values-example.yaml Tag Consistency

In deployments/helm/values-example.yaml:

image:
  repository: ghcr.io/lsflk/argus
  tag: "1.0.0"
  • build-image.yml publishes :latest and :<sha>. If users copy values-example.yaml as-is, 1.0.0 will fail to pull. Aligning this with latest or documenting the placeholder would be helpful.

6. 💡 .dockerignore

Consider adding common IDE and env files to .dockerignore:

.idea
.vscode
*.env*
coverage.out

Rebuild the container on Dockerfile/Go PRs without pushing, force
imagePullPolicy Always when the chart tag is latest, and align the
example values with published tags.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ginaxu1
ginaxu1 requested a review from mushrafmim September 2, 2026 05:16
@ginaxu1

ginaxu1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks @mushrafmim addressed

@mushrafmim

Copy link
Copy Markdown
Contributor

💡 Suggestion: Standardize on ARGUS_API_KEY across Helm & Docs

While verifying the container end-to-end against Postgres, we noticed that internal/middleware/auth.go and the client SDK (pkg/audit/client.go) both expect the API key under ARGUS_API_KEY / APIKey:

  • internal/middleware/auth.go:14: apiKey := os.Getenv("ARGUS_API_KEY")
  • pkg/audit/client.go:43: APIKey string

However, the Helm chart templates and documentation currently configure and reference ARGUS_AUTH_TOKEN / auth.token, which causes the service to fail closed (401 Unauthorized: Server authentication is not configured) when deploying via Helm with auth.token.

Could we standardize everything on API_KEY / ARGUS_API_KEY? Here are all the places to update:

  1. deployments/helm/argus/templates/deployment.yaml (lines 41-46):
    Change ARGUS_AUTH_TOKEN to ARGUS_API_KEY:

    - name: ARGUS_API_KEY
      valueFrom:
        secretKeyRef:
          name: {{ .Values.auth.existingSecret | default (printf "%s-credentials" (include "argus.fullname" .)) }}
          key: {{ if .Values.auth.existingSecret }}api-key{{ else }}ARGUS_API_KEY{{ end }}
          optional: true
  2. deployments/helm/argus/templates/secrets.yaml (line 11):
    Change ARGUS_AUTH_TOKEN to ARGUS_API_KEY:

    ARGUS_API_KEY: {{ .Values.auth.apiKey | default .Values.auth.token | default "" | quote }}
  3. deployments/helm/argus/templates/external-secrets.yaml (lines 29-32):
    Change ARGUS_AUTH_TOKEN to ARGUS_API_KEY:

    - secretKey: ARGUS_API_KEY
      remoteRef:
        key: {{ .Values.auth.externalSecrets.remoteDbKey | quote }}
        property: "argus_api_key"
  4. deployments/helm/argus/values.yaml (under auth:):
    Add the default parameter:

    auth:
      username: "postgres"
      password: ""
      apiKey: ""
      existingSecret: ""
  5. deployments/helm/values-example.yaml (under auth:):
    Include an example API key:

    auth:
      username: "postgres"
      password: "example-db-password"
      apiKey: "example-api-key"
      existingSecret: ""
  6. deployments/helm/argus/README.md (Configuration Parameters table):
    Add auth.apiKey:

    | `auth.apiKey` | API key for Bearer authentication (`ARGUS_API_KEY`) | `""` |
  7. README.md (line 175):
    Update the environment variables table:

    | `ARGUS_API_KEY` | - | API key required for Bearer authentication (`Authorization: Bearer <key>`). |
  8. internal/config/README.md (line 81):
    Update the configuration table:

    | `ARGUS_API_KEY` | **Yes** | - | A high-entropy API key required for all API write operations. Argus fails closed if this is missing. |
  9. docker-compose.yml (under argus.environment):
    Add ARGUS_API_KEY=dev-api-key so local docker-compose works out of the box.

  10. (Optional) internal/middleware/auth.go (line 14):
    Add fallback for smooth backward compatibility:

    apiKey := os.Getenv("ARGUS_API_KEY")
    if apiKey == "" {
        apiKey = os.Getenv("ARGUS_AUTH_TOKEN")
    }

@mushrafmim

Copy link
Copy Markdown
Contributor

💡 Follow-up: Treat authentication strictly as an API Key (not a Bearer token)

To follow up on the ARGUS_API_KEY standardization: currently, the middleware (internal/middleware/auth.go) strictly enforces the Authorization: Bearer <token> header format, and docs describe it as a "Bearer token".

Since the secret is a static pre-shared API key rather than a dynamic/OAuth token, we should treat it as an API key across both code and docs:

  1. internal/middleware/auth.go:

    • Allow standard API key headers such as X-API-Key in addition to Authorization: Bearer <key> (for backward compatibility):
      // Check X-API-Key header first, fall back to Authorization: Bearer
      token := r.Header.Get("X-API-Key")
      if token == "" {
          authHeader := r.Header.Get("Authorization")
          if parts := strings.Split(authHeader, " "); len(parts) == 2 && strings.EqualFold(parts[0], "bearer") {
              token = parts[1]
          }
      }
    • Update error messages from "Invalid token" to "Invalid API key" and "Missing API key".
  2. README.md & internal/config/README.md:

    • Replace "Bearer token authentication" with "API key authentication".
    • Update curl examples to show -H "X-API-Key: <your-api-key>" (or -H "Authorization: Bearer <your-api-key>").
  3. docs/API.md:

    • Document the X-API-Key (and Authorization: Bearer) header requirement in the API reference examples.
  4. CLAUDE.md:

    • Update line 99 from "SHA-256 pre-hash of the bearer token" to "SHA-256 pre-hash of the API key".

Co-authored-by: Cursor <cursoragent@cursor.com>
@ginaxu1

ginaxu1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

@mushrafmim on the original review:

  1. PR image validation: Resolved. pull_request is back on build-image.yml; registry login and push only run when github.event_name != 'pull_request'.

  2. latest + IfNotPresent: Resolved. The chart now sets imagePullPolicy: Always when image.tag is latest, and keeps IfNotPresent when a SHA (or other pin) is used.

  3. Chart 0.1.1 publish steps: No action in this PR (process, not code). After merge: wait for the image job, then dispatch Build and Push Development Helm Chart with version=0.1.1. Documented in deployments/helm/argus/README.md.

  4. GHCR package visibility: No action in this PR (org admin). After the first image push, set ghcr.io/lsflk/argus to public under https://github.com/orgs/LSFLK/packages. Also noted in the Helm README.

  5. values-example.yaml tag: Resolved. Example tag is latest, with a note that 1.0.0 is not published.

  6. .dockerignore: Resolved. Added .idea, .vscode, *.env*, and coverage.out

@ginaxu1

ginaxu1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

@mushrafmim on standardizing ARGUS_API_KEY:

Resolved. Helm was injecting ARGUS_AUTH_TOKEN while the server reads ARGUS_API_KEY, which fail-closed with 401 Server authentication is not configured.

  • Deployment env, generated secret, and ExternalSecret now use ARGUS_API_KEY / auth.apiKey (existing secrets still use key api-key).
  • auth.token remains a values fallback when generating the secret.
  • Docs, example values, and docker-compose (ARGUS_API_KEY=dev-api-key) updated.
  • Optional env fallback to ARGUS_AUTH_TOKEN is in middleware for older deploys.

pkg/audit already used APIKey; no client field rename needed.

@ginaxu1

ginaxu1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

@mushrafmim on treating auth as an API key (not a Bearer token):

Resolved on the server and docs. The credential is a static pre-shared key, so naming and errors now say API key.

  • Middleware accepts X-API-Key first, then Authorization: Bearer <key>.
  • Error strings are Missing API key / Invalid API key.
  • CORS allows X-API-Key.
  • README, internal/config/README.md, docs/API.md, and CLAUDE.md updated.

No action on the Go client send path. pkg/audit still sends Authorization: Bearer so existing callers keep working; the server accepts both.

@mushrafmim

Copy link
Copy Markdown
Contributor

@mushrafmim on treating auth as an API key (not a Bearer token):

Resolved on the server and docs. The credential is a static pre-shared key, so naming and errors now say API key.

  • Middleware accepts X-API-Key first, then Authorization: Bearer <key>.
  • Error strings are Missing API key / Invalid API key.
  • CORS allows X-API-Key.
  • README, internal/config/README.md, docs/API.md, and CLAUDE.md updated.

No action on the Go client send path. pkg/audit still sends Authorization: Bearer so existing callers keep working; the server accepts both.

Hi, I don't think we need support for bearer tokens, since there's nobody is gonna issue that, and we have to perform signature validation. for now, I think, going with API_KEYs are enough, and later after getting the features working, we can add direct support for IDPs. Other than this, everything LGTM.

Drop Authorization Bearer support. Request signing stays separate;
IDP/Bearer can land later once the API key path is working.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ginaxu1

ginaxu1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

@mushrafmim on dropping Bearer: Resolved.

Auth is X-API-Key only (middleware + pkg/audit client). Bearer is no longer accepted. Request signatures stay as they are; IDP/Bearer can come later once this path is working.

@mushrafmim

Copy link
Copy Markdown
Contributor

@mushrafmim on dropping Bearer: Resolved.

Auth is X-API-Key only (middleware + pkg/audit client). Bearer is no longer accepted. Request signatures stay as they are; IDP/Bearer can come later once this path is working.

Thanks for addressing. LGTM!

@mushrafmim
mushrafmim merged commit 85d5ea5 into main Sep 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants