Skip to content

fix: Enforce workflow namespace authorization#3780

Open
kfelternv wants to merge 4 commits into
NVIDIA:mainfrom
kfelternv:codex/workflow-hardening
Open

fix: Enforce workflow namespace authorization#3780
kfelternv wants to merge 4 commits into
NVIDIA:mainfrom
kfelternv:codex/workflow-hardening

Conversation

@kfelternv

@kfelternv kfelternv commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Adds a NICo-specific Temporal server that maps client-certificate identities and restricts workflow service calls to the permitted cluster operations and namespaces. It also builds and packages that server for the REST local-development and production paths.

Related issues

None.

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required (docs, internal refactor, etc.)

Additional Notes

Draft pending local Kind/DevSpace verification.

@copy-pr-bot

copy-pr-bot Bot commented Jul 21, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Summary by CodeRabbit

  • New Features
    • Added a dedicated Temporal server image for local and production deployments.
    • Local Kind environments now build and load the Temporal server automatically.
    • Introduced certificate-based identity mapping and authorization for Temporal services.
    • Added a Temporal server command to validate dynamic configuration files.
  • Bug Fixes
    • Improved authorization handling for health checks, namespaces, and service-specific access.
  • Tests
    • Expanded formatting, linting, vetting, and automated test coverage for the Temporal server.

Walkthrough

Adds a standalone Temporal server with certificate-based authorization, custom CLI startup, Docker packaging, local kind integration, and CI checks and image publishing.

Changes

Temporal server integration

Layer / File(s) Summary
Certificate identity and authorization policy
rest-api/temporal-server/go.mod, rest-api/temporal-server/internal/auth/*
Adds TLS certificate identity mapping, namespace-aware authorization rules, and table-driven authorization tests.
CLI and server runtime
rest-api/temporal-server/cmd/server/main.go, rest-api/docker/*/Dockerfile.nico-temporal-server, rest-api/THIRD-PARTY-LICENSES
Adds CLI commands for dynamic-config validation and server startup, plus local and production container builds.
Local image and kind deployment
rest-api/Makefile, dev/deployment/devspace/bootstrap-prereqs.sh, rest-api/temporal-helm/temporal/values*.yaml
Adds Temporal tests and image targets, builds and loads the image into kind, and configures local and deployed Helm values to use the new image.
CI checks and image publishing
.github/workflows/rest-lint-and-test.yml, .github/workflows/rest-build-push-docker.yml
Runs formatting, linting, vetting, and tests for the Temporal module and publishes its image with build summaries and artifact metadata.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant startServer
  participant NewClaimMapper
  participant NewAuthorizer
  participant TemporalServer
  CLI->>startServer: start command and service options
  startServer->>NewClaimMapper: configure certificate claim mapping
  startServer->>NewAuthorizer: configure authorization policy
  startServer->>TemporalServer: initialize and start selected services
  TemporalServer-->>CLI: stopped-server status
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the core auth-enforcement change in the new Temporal server.
Description check ✅ Passed The description is directly related to the added Temporal server, authorization logic, and packaging changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

Signed-off-by: Kyle Felter <kfelter@nvidia.com>
Signed-off-by: Kyle Felter <kfelter@nvidia.com>
@kfelternv

Copy link
Copy Markdown
Contributor Author

What changed

This PR adds certificate-identity authorization to the NICo Temporal server and uses that server in local Kind/DevSpace. I exercised the clean bootstrap ordering, the live server image, mutual TLS, and every distinct admin, control, site, flow, and unknown-identity authorization branch at head d2715beceddc68fc4f8c50e5d682ade54c75b1bd.

Scenario and setup

I used a dedicated development VM, a clean isolated checkout at the tested head, an isolated kubeconfig, and a new Kind cluster:

HEAD=d2715beceddc68fc4f8c50e5d682ade54c75b1bd
CLUSTER=pr3780
CTX="kind-${CLUSTER}"
export KUBECONFIG="$PWD/.pr3780-kubeconfig"

git checkout "$HEAD"
test "$(git rev-parse HEAD)" = "$HEAD"
kind create cluster --name "$CLUSTER" --kubeconfig "$KUBECONFIG"

After the clean Temporal bootstrap, I created cert-manager Certificate resources in an isolated pr3780-verify namespace. They used the local nico-rest-ca-issuer and represented the four non-admin identity mappings:

NAME             CN                                                       DNS                                                        READY
control-client   temporal-client                                          [nico-rest-api]                                            True
flow-client      temporal-client                                          [flow]                                                     True
site-client      11111111-1111-1111-1111-111111111111.client.nico.local   [11111111-1111-1111-1111-111111111111.client.nico.local]   True
unknown-client   temporal-client                                          [unknown]                                                  True

A temporalio/admin-tools:1.26.2 verifier pod mounted those four certificate secrets. The Helm admin-tools pod mounted the interservice certificate for admin checks. The commands below used these shared definitions:

VERIFY_NS=pr3780-verify
VERIFY_POD=temporal-verifier
TEMPORAL_ADDRESS=temporal-frontend.temporal:7233
SERVER_NAME=interservice.server.temporal.local

run_temporal() {
  role=$1
  shift
  kubectl --context "$CTX" -n "$VERIFY_NS" exec "$VERIFY_POD" -- \
    temporal "$@" \
    --address "$TEMPORAL_ADDRESS" \
    --tls-cert-path "/certs/${role}/tls.crt" \
    --tls-key-path "/certs/${role}/tls.key" \
    --tls-ca-path "/certs/${role}/ca.crt" \
    --tls-server-name "$SERVER_NAME" \
    --command-timeout 15s \
    --color never
}

expect_denied() {
  label=$1
  role=$2
  shift 2
  if output=$(run_temporal "$role" "$@" 2>&1); then
    echo "FAIL ${label} was allowed"
    return 1
  fi
  case "$output" in
    *unauthorized*|*Unauthorized*|*PermissionDenied*|*"not authorized"*|*"permission denied"*)
      echo "PASS ${label} denied"
      ;;
    *)
      printf 'FAIL %s returned an unexpected error: %s\n' "$label" "$output"
      return 1
      ;;
  esac
}

Verification

Step 1: Build and load the custom Temporal server before Helm waits

Why this step exists: A clean cluster previously failed because Helm referenced localhost:5000/nico-temporal-server:latest with pullPolicy: Never before that image existed in Kind.

Runnable command:

devspace purge \
  --kubeconfig "$KUBECONFIG" \
  --kube-context "$CTX" \
  -n nico-system \
  --no-colors \
  --no-warn

Observed result:

[local-dev] Building localhost:5000/nico-temporal-server:latest
...
[local-dev] Loading localhost:5000/nico-temporal-server:latest into kind-pr3780
Image: "localhost:5000/nico-temporal-server:latest" ... not yet present on node "pr3780-control-plane", loading...
[local-dev] Installing Temporal
Temporal namespace confirmed: cloud
Temporal namespace confirmed: site
[local-dev] Bootstrap complete

Why this proves the behavior: The clean bootstrap built and loaded the exact image before installing and waiting for Temporal.

Step 2: Run all four Temporal services from the custom image

Why this step exists: A successful image build is not proof that the Temporal services actually use it.

Runnable command:

kubectl --context "$CTX" -n temporal get deployment \
  temporal-frontend temporal-history temporal-matching temporal-worker \
  -o custom-columns='NAME:.metadata.name,READY:.status.readyReplicas,DESIRED:.spec.replicas,IMAGE:.spec.template.spec.containers[0].image'

Observed result:

NAME                READY   DESIRED   IMAGE
temporal-frontend   1       1         localhost:5000/nico-temporal-server:latest
temporal-history    1       1         localhost:5000/nico-temporal-server:latest
temporal-matching   1       1         localhost:5000/nico-temporal-server:latest
temporal-worker     1       1         localhost:5000/nico-temporal-server:latest

Why this proves the behavior: Every Temporal server role was ready and running the PR's custom server image.

Step 3: Allow cluster read operations for the control identity

Why this step exists: The control identity must be able to perform read-only cluster-scope operations.

Runnable command:

run_temporal control operator namespace list -o json >/dev/null
echo "PASS control cluster namespace list allowed"

Observed result:

PASS control cluster namespace list allowed

Why this proves the behavior: The live frontend accepted ListNamespaces for the control certificate.

Step 4: Restrict namespace registration to canonical lowercase UUIDs

Why this step exists: The control identity may register site namespaces, but not arbitrary or non-canonical names.

Runnable command:

run_temporal control operator namespace create \
  --namespace aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa \
  --retention 24h >/dev/null
echo "PASS lowercase canonical UUID registration allowed"

expect_denied "uppercase UUID registration" control \
  operator namespace create \
  --namespace BBBBBBBB-BBBB-4BBB-8BBB-BBBBBBBBBBBB \
  --retention 24h

Observed result:

PASS lowercase canonical UUID registration allowed
PASS uppercase UUID registration denied

Why this proves the behavior: Registration accepted the canonical site namespace and rejected the non-canonical uppercase UUID.

Step 5: Enforce control workflow namespace boundaries

Why this step exists: The control identity is a writer for cloud, site, and UUID site namespaces, but not flow.

Runnable command:

run_temporal control workflow start \
  --namespace cloud --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-control-cloud >/dev/null
echo "PASS control cloud workflow allowed"

run_temporal control workflow start \
  --namespace site --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-control-site >/dev/null
echo "PASS control shared site workflow allowed"

run_temporal control workflow start \
  --namespace 11111111-1111-1111-1111-111111111111 \
  --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-control-site-uuid >/dev/null
echo "PASS control UUID workflow allowed"

expect_denied "control flow workflow" control workflow start \
  --namespace flow --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-control-flow

Observed result:

PASS control cloud workflow allowed
PASS control shared site workflow allowed
PASS control UUID workflow allowed
PASS control flow workflow denied

Why this proves the behavior: The same live StartWorkflowExecution method followed the intended namespace-specific allow and deny decisions.

Step 6: Deny operator APIs for the control identity

Why this step exists: Cluster read access must not grant the control identity unrestricted Operator Service access.

Runnable command:

expect_denied "control operator API" control operator search-attribute list

Observed result:

PASS control operator API denied

Why this proves the behavior: The control certificate could not call the Operator Service.

Step 7: Enforce site identity namespace boundaries

Why this step exists: A site identity is a writer only for the shared site namespace and its own UUID namespace.

Runnable command:

run_temporal site workflow start \
  --namespace site --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-site-shared >/dev/null
echo "PASS site identity shared site workflow allowed"

run_temporal site workflow start \
  --namespace 11111111-1111-1111-1111-111111111111 \
  --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-site-own >/dev/null
echo "PASS site identity own UUID workflow allowed"

expect_denied "site identity other UUID workflow" site workflow start \
  --namespace 22222222-2222-2222-2222-222222222222 \
  --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-site-other

expect_denied "site identity cloud workflow" site workflow start \
  --namespace cloud --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-site-cloud

expect_denied "site identity flow workflow" site workflow start \
  --namespace flow --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-site-flow

Observed result:

PASS site identity shared site workflow allowed
PASS site identity own UUID workflow allowed
PASS site identity other UUID workflow denied
PASS site identity cloud workflow denied
PASS site identity flow workflow denied

Why this proves the behavior: The site certificate was confined to the shared site namespace and the UUID encoded in its certificate identity.

Step 8: Enforce flow identity namespace boundaries

Why this step exists: The flow identity is a writer only for the flow namespace.

Runnable command:

run_temporal flow workflow start \
  --namespace flow --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-flow-own >/dev/null
echo "PASS flow identity flow workflow allowed"

expect_denied "flow identity site workflow" flow workflow start \
  --namespace site --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-flow-site

expect_denied "flow identity cloud workflow" flow workflow start \
  --namespace cloud --task-queue pr3780-verify \
  --type VerifyWorkflow --workflow-id verify-flow-cloud

Observed result:

PASS flow identity flow workflow allowed
PASS flow identity site workflow denied
PASS flow identity cloud workflow denied

Why this proves the behavior: The live frontend allowed only the flow namespace for the flow certificate.

Step 9: Allow health checks but deny application APIs for an unknown identity

Why this step exists: Unknown verified certificates may reach health checks but must not gain Temporal API access.

Runnable command:

run_temporal unknown operator cluster health
expect_denied "unknown identity namespace list" unknown operator namespace list

Observed result:

SERVING
PASS unknown identity namespace list denied

Why this proves the behavior: The health exception remained available while the same unknown certificate was denied a cluster read API.

Step 10: Require a client certificate at the mutual-TLS boundary

Why this step exists: Authorization must not be reachable without a verified client certificate.

Runnable command:

kubectl --context "$CTX" -n "$VERIFY_NS" exec "$VERIFY_POD" -- \
  temporal operator cluster health \
  --address "$TEMPORAL_ADDRESS" \
  --tls \
  --tls-ca-path /certs/unknown/ca.crt \
  --tls-server-name "$SERVER_NAME" \
  --command-timeout 15s \
  --color never

Observed result:

failed reaching server: ... write: broken pipe
command terminated with exit code 1

Why this proves the behavior: The server rejected the TLS connection before serving the health request when no client certificate was supplied.

Step 11: Allow unrestricted admin operator access

Why this step exists: The interservice admin certificate must retain full access after the custom authorizer is enabled.

Runnable command:

ADMIN_POD=$(kubectl --context "$CTX" -n temporal get pod \
  -l app.kubernetes.io/component=admintools \
  -o jsonpath='{.items[0].metadata.name}')

kubectl --context "$CTX" -n temporal exec "$ADMIN_POD" -- \
  temporal operator search-attribute list \
  --namespace cloud \
  --address "$TEMPORAL_ADDRESS" \
  --tls-cert-path /var/secrets/temporal/certs/server-interservice/tls.crt \
  --tls-key-path /var/secrets/temporal/certs/server-interservice/tls.key \
  --tls-ca-path /var/secrets/temporal/certs/server-interservice/ca.crt \
  --tls-server-name "$SERVER_NAME" \
  --command-timeout 15s \
  --color never >/dev/null
echo "PASS admin identity operator API allowed"

Observed result:

PASS admin identity operator API allowed

Why this proves the behavior: The admin certificate could call the Operator Service that the control identity was denied.

Step 12: Run the focused Temporal server tests

Why this step exists: The live checks cover representative public calls; the focused package tests cover the full claim-mapping and method-metadata branch table.

Runnable command:

cd rest-api/temporal-server
go test ./... -count=1

Observed result:

?    github.com/NVIDIA/infra-controller/rest-api/temporal-server/cmd/server       [no test files]
ok   github.com/NVIDIA/infra-controller/rest-api/temporal-server/internal/auth    0.544s

Why this proves the behavior: The complete focused authorization test package passed at the same head used by the live cluster.

A supplementary full application devspace deploy compiled and loaded the branch images, then stopped at Helm because dev/deployment/devspace/values.base.yaml currently contains a duplicate legacyAlias key. That file is identical between current main and this PR (git diff --exit-code upstream/main...HEAD -- dev/deployment/devspace/values.base.yaml returned 0), so this was classified as a pre-existing unrelated check rather than a changed-interface failure.

@kfelternv
kfelternv marked this pull request as ready for review July 23, 2026 18:17
@kfelternv
kfelternv requested review from a team as code owners July 23, 2026 18:17
@github-actions

Copy link
Copy Markdown

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-07-23 18:21:05 UTC | Commit: d2715be

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2715beced

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +32 to +34
repository: localhost:5000/nico-temporal-server
tag: latest
pullPolicy: Never

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Wire the authorized image into production Helm

For non-Kind Helm installs this override is never read; only values-kind.yaml now points at nico-temporal-server, while the default rest-api/temporal-helm/temporal/values.yaml still uses server.image.repository: temporalio/server. That means production Temporal pods keep running the upstream server without the new claim mapper/authorizer, so the namespace authorization fix is not actually enforced outside local Kind.

Useful? React with 👍 / 👎.

Comment thread rest-api/temporal-server/cmd/server/main.go Outdated
Comment thread rest-api/docker/production/Dockerfile.nico-temporal-server Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/rest-lint-and-test.yml (2)

265-270: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Go module cache not extended for the new temporal-server matrix entry.

style (Lines 33-35) and lint-go (Lines 79-81) jobs were updated to include rest-api/temporal-server/go.sum in cache-dependency-path, but the test job's "Set up Go" step still only references rest-api/go.sum even though the matrix (Line 246) now runs make rest-api/test-temporal-server, which downloads a separate, large dependency tree. This causes cache misses on every CI run for the temporal-server module's tests.

🔧 Proposed fix
       - name: Set up Go
         uses: actions/setup-go@v5
         with:
           go-version: ${{ env.GO_VERSION }}
           cache: true
-          cache-dependency-path: rest-api/go.sum
+          cache-dependency-path: |
+            rest-api/go.sum
+            rest-api/temporal-server/go.sum
🤖 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/rest-lint-and-test.yml around lines 265 - 270, Update the
test job’s “Set up Go” step to include rest-api/temporal-server/go.sum alongside
rest-api/go.sum in cache-dependency-path, matching the existing style and
lint-go job configuration for the temporal-server matrix tests.

Source: Path instructions


93-98: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

golangci-lint step isn't extended to the new temporal-server module.

go fmt, revive, and go vet were all duplicated for temporal-server, but this golangci-lint step still only lints rest-api (working-directory: rest-api, args: ... ./...). The new module ships without golangci-lint coverage.

🤖 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/rest-lint-and-test.yml around lines 93 - 98, Extend the
“Run golangci-lint” workflow step to lint both the existing rest-api module and
the new temporal-server module, preserving the current timeout and exit-code
settings. Update the working-directory and target configuration so ./... is
executed for each module, matching the duplicated go fmt, revive, and go vet
coverage.

Source: Path instructions

🧹 Nitpick comments (4)
rest-api/temporal-server/internal/auth/authorizer.go (1)

103-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate canonical-UUID validation logic.

This canonical-UUID check (uuid.Parse + string round-trip equality) is reimplemented independently in claim_mapper.go's mapIdentity (lines 86-93). See consolidated comment.

🤖 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 `@rest-api/temporal-server/internal/auth/authorizer.go` around lines 103 - 106,
Consolidate the canonical UUID validation used by isSiteNamespace and
claim_mapper.go’s mapIdentity instead of maintaining duplicate uuid.Parse plus
string round-trip logic. Reuse isSiteNamespace or extract a shared validation
helper, preserving the existing requirement that parsing succeeds and the
canonical string exactly matches the input.
dev/deployment/devspace/bootstrap-prereqs.sh (1)

556-568: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the Makefile's build/load targets instead of duplicating them here.

rest-api/Makefile already defines docker-build-local/kind-load targets that build and load nico-temporal-server with the same registry/tag conventions. Inlining an independent docker build/kind load here risks drifting from the Makefile's build flags over time.

♻️ Proposed direction
-      log "Building ${temporal_image}"
-      docker build -t "${temporal_image}" \
-        -f "${REPO_ROOT}/rest-api/docker/local/Dockerfile.nico-temporal-server" \
-        "${REPO_ROOT}/rest-api"
-
-      log "Loading ${temporal_image} into ${current_context}"
-      kind load docker-image --name "${current_context#kind-}" "${temporal_image}"
+      log "Building and loading ${temporal_image}"
+      make -C "${REPO_ROOT}/rest-api" docker-build-local kind-load \
+        KIND_CLUSTER_NAME="${current_context#kind-}"
🤖 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 `@dev/deployment/devspace/bootstrap-prereqs.sh` around lines 556 - 568, Replace
the inline docker build and kind load commands in the kind-* bootstrap branch
with calls to the existing rest-api Makefile targets docker-build-local and
kind-load. Pass the current kind context as required by kind-load, and preserve
the surrounding prerequisite checks and logging.
rest-api/docker/production/Dockerfile.nico-temporal-server (2)

21-21: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pin the third-party base image by digest in production.

temporalio/server:1.26.2 is a mutable tag pulled from a third-party registry. Based on learnings, this repo's threat model only exempts trusted NVIDIA distroless images from digest-pinning scrutiny; a third-party Temporal image doesn't fall under that carve-out, so pinning by digest here would harden the production build against upstream tag mutation.

🔒 Proposed fix
-FROM temporalio/server:1.26.2
+FROM temporalio/server:1.26.2@sha256:<digest>
🤖 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 `@rest-api/docker/production/Dockerfile.nico-temporal-server` at line 21,
Update the production Dockerfile’s temporalio/server base image reference to
include its immutable registry digest while retaining the 1.26.2 image version.
Apply the change to the FROM declaration only, using the verified digest for
that exact third-party image.

Source: Learnings


4-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Local and production Dockerfiles are byte-for-byte identical. Both build stages, COPY/RUN steps, and the final temporalio/server:1.26.2 base are duplicated verbatim across the two files, which will drift silently if one is updated without the other.

  • rest-api/docker/production/Dockerfile.nico-temporal-server#L4-L23: keep this as the canonical definition (with the digest-pinning fix noted separately) and derive the local variant from it (e.g., via a shared base stage, a build-arg-driven single Dockerfile, or a generation script) rather than maintaining two copies.
  • rest-api/docker/local/Dockerfile.nico-temporal-server#L4-L23: replace with a thin wrapper over the production definition, or document explicitly why an independent copy is required for local dev.
🤖 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 `@rest-api/docker/production/Dockerfile.nico-temporal-server` around lines 4 -
23, Eliminate the duplicated Dockerfile definitions by keeping the production
Dockerfile.nico-temporal-server as the canonical build and converting the local
Dockerfile.nico-temporal-server into a thin wrapper or generated/shared
reference; preserve the existing build stages and base image behavior, and
explicitly document the local variant only if an independent definition is
required. Apply the corresponding change in
rest-api/docker/production/Dockerfile.nico-temporal-server lines 4-23 and
rest-api/docker/local/Dockerfile.nico-temporal-server lines 4-23.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@rest-api/temporal-server/cmd/server/main.go`:
- Around line 33-36: Update main to handle the error returned by
app.Run(os.Args): preserve successful execution, but when a top-level parsing or
dispatch error is returned, report it through the CLI’s established error/exit
mechanism so the process exits non-zero. Use the existing app and buildCLI flow
without changing subcommand behavior.

In `@rest-api/temporal-server/go.mod`:
- Line 14: Update the google.golang.org/grpc dependency in go.mod from v1.67.1
to v1.79.3 or later, ensuring the module metadata and checksums remain
consistent with the selected version.

In `@rest-api/temporal-server/internal/auth/authorizer_test.go`:
- Around line 158-165: Update the Authorize test assertions in
authorizer_test.go to use the project's testify assertion helpers instead of raw
t.Fatalf and t.Errorf calls, preserving the existing error and decision checks
and their failure messages.

In `@rest-api/temporal-server/internal/auth/claim_mapper_test.go`:
- Around line 76-89: The GetClaims test assertions in claim_mapper_test.go
should use testify assertions instead of raw t.Fatalf and t.Errorf calls.
Replace the error, extension type, identity kind, and site namespace checks with
the project’s established testify assertion style, preserving the existing
failure conditions and messages.

---

Outside diff comments:
In @.github/workflows/rest-lint-and-test.yml:
- Around line 265-270: Update the test job’s “Set up Go” step to include
rest-api/temporal-server/go.sum alongside rest-api/go.sum in
cache-dependency-path, matching the existing style and lint-go job configuration
for the temporal-server matrix tests.
- Around line 93-98: Extend the “Run golangci-lint” workflow step to lint both
the existing rest-api module and the new temporal-server module, preserving the
current timeout and exit-code settings. Update the working-directory and target
configuration so ./... is executed for each module, matching the duplicated go
fmt, revive, and go vet coverage.

---

Nitpick comments:
In `@dev/deployment/devspace/bootstrap-prereqs.sh`:
- Around line 556-568: Replace the inline docker build and kind load commands in
the kind-* bootstrap branch with calls to the existing rest-api Makefile targets
docker-build-local and kind-load. Pass the current kind context as required by
kind-load, and preserve the surrounding prerequisite checks and logging.

In `@rest-api/docker/production/Dockerfile.nico-temporal-server`:
- Line 21: Update the production Dockerfile’s temporalio/server base image
reference to include its immutable registry digest while retaining the 1.26.2
image version. Apply the change to the FROM declaration only, using the verified
digest for that exact third-party image.
- Around line 4-23: Eliminate the duplicated Dockerfile definitions by keeping
the production Dockerfile.nico-temporal-server as the canonical build and
converting the local Dockerfile.nico-temporal-server into a thin wrapper or
generated/shared reference; preserve the existing build stages and base image
behavior, and explicitly document the local variant only if an independent
definition is required. Apply the corresponding change in
rest-api/docker/production/Dockerfile.nico-temporal-server lines 4-23 and
rest-api/docker/local/Dockerfile.nico-temporal-server lines 4-23.

In `@rest-api/temporal-server/internal/auth/authorizer.go`:
- Around line 103-106: Consolidate the canonical UUID validation used by
isSiteNamespace and claim_mapper.go’s mapIdentity instead of maintaining
duplicate uuid.Parse plus string round-trip logic. Reuse isSiteNamespace or
extract a shared validation helper, preserving the existing requirement that
parsing succeeds and the canonical string exactly matches the input.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 80880ee6-0085-49e2-a7f3-d72b5d79315e

📥 Commits

Reviewing files that changed from the base of the PR and between c853e78 and d2715be.

⛔ Files ignored due to path filters (1)
  • rest-api/temporal-server/go.sum is excluded by !**/*.sum
📒 Files selected for processing (14)
  • .github/workflows/rest-build-push-docker.yml
  • .github/workflows/rest-lint-and-test.yml
  • dev/deployment/devspace/bootstrap-prereqs.sh
  • rest-api/Makefile
  • rest-api/THIRD-PARTY-LICENSES
  • rest-api/docker/local/Dockerfile.nico-temporal-server
  • rest-api/docker/production/Dockerfile.nico-temporal-server
  • rest-api/temporal-helm/temporal/values-kind.yaml
  • rest-api/temporal-server/cmd/server/main.go
  • rest-api/temporal-server/go.mod
  • rest-api/temporal-server/internal/auth/authorizer.go
  • rest-api/temporal-server/internal/auth/authorizer_test.go
  • rest-api/temporal-server/internal/auth/claim_mapper.go
  • rest-api/temporal-server/internal/auth/claim_mapper_test.go

Comment thread rest-api/temporal-server/cmd/server/main.go
Comment thread rest-api/temporal-server/go.mod Outdated
Comment thread rest-api/temporal-server/internal/auth/authorizer_test.go Outdated
Comment thread rest-api/temporal-server/internal/auth/claim_mapper_test.go Outdated
Signed-off-by: Kyle Felter <kfelter@nvidia.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@rest-api/temporal-helm/temporal/values.yaml`:
- Around line 40-43: Replace the image.tag value under the Temporal server image
configuration with an immutable release or CI-generated tag, and ensure release
automation publishes the required architecture-specific image using that tag.
Keep latest only for explicitly local-only configurations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7ae1be6b-8ccb-4d83-968c-4162fc9a0b34

📥 Commits

Reviewing files that changed from the base of the PR and between d2715be and d37b661.

⛔ Files ignored due to path filters (1)
  • rest-api/temporal-server/go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • .github/workflows/rest-lint-and-test.yml
  • rest-api/docker/production/Dockerfile.nico-temporal-server
  • rest-api/temporal-helm/temporal/values.yaml
  • rest-api/temporal-server/cmd/server/main.go
  • rest-api/temporal-server/go.mod
  • rest-api/temporal-server/internal/auth/authorizer_test.go
  • rest-api/temporal-server/internal/auth/claim_mapper.go
  • rest-api/temporal-server/internal/auth/claim_mapper_test.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • rest-api/docker/production/Dockerfile.nico-temporal-server
  • rest-api/temporal-server/go.mod
  • rest-api/temporal-server/internal/auth/claim_mapper.go
  • rest-api/temporal-server/internal/auth/authorizer_test.go
  • .github/workflows/rest-lint-and-test.yml
  • rest-api/temporal-server/internal/auth/claim_mapper_test.go
  • rest-api/temporal-server/cmd/server/main.go

Comment on lines 40 to 43
image:
repository: temporalio/server
tag: 1.22.6
repository: nvcr.io/0837451325059433/carbide-dev/nico-temporal-server
tag: latest
pullPolicy: IfNotPresent

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use an immutable image tag instead of latest.

With latest and IfNotPresent, nodes can retain an older cached image while new nodes pull a different image. This makes deployments non-reproducible and can leave Temporal services running mixed server versions. Have release automation publish the required architecture-specific image and set this value to an immutable release/CI tag; reserve latest for explicitly local-only values.

🤖 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 `@rest-api/temporal-helm/temporal/values.yaml` around lines 40 - 43, Replace
the image.tag value under the Temporal server image configuration with an
immutable release or CI-generated tag, and ensure release automation publishes
the required architecture-specific image using that tag. Keep latest only for
explicitly local-only configurations.

Source: Path instructions

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.

1 participant