Skip to content

ci: deploy cippkvupn-proc in lockstep with cippkvupn - #4

Merged
robgilbreath merged 1 commit into
masterfrom
ci/deploy-proc-app-in-lockstep
Sep 11, 2026
Merged

robgilbreath merged 1 commit into
masterfrom
ci/deploy-proc-app-in-lockstep

Conversation

@robgilbreath

Copy link
Copy Markdown

What

Adds a second Azure/functions-action step to the existing master_cippkvupn.yml deploy job so that cippkvupn-proc is deployed from the same workflow run, from the same checkout, as cippkvupn.

cippkvupn-proc (Y1 Consumption, plan cipp-srv-kvupnproc) is the offload/processor node for cippkvupn. It was created and hand-deployed manually and had no CI/CD at all — its scmType was None. Without this, it silently rots at whatever version was last hand-pushed.

Why this matters — version lockstep

CIPP only dispatches timers to an offload node when that node's version is an exact match for the main app's. From Modules/CIPPCore/Public/Get-CIPPTimerFunctions.ps1:

$AvailableNodes = $Nodes | Where-Object { (Test-CippOffloadFunctionApp -SiteName $_.RowKey) -and $_.Version -eq $MainFunctionVersion } | ForEach-Object { Get-CippOffloadSuffix -SiteName $_.RowKey }

If the versions drift there is no error and no warning — the node just disappears from $AvailableNodes. The failure mode is worse than "offloading stops":

$RunOnProcessor = $true
if ($Config -and $Config.state -eq $true -and $AvailableNodes.Count -gt 0) {
    if ($env:CIPP_PROCESSOR -ne 'true') { $RunOnProcessor = $false }
}

With zero available nodes, the main app keeps $RunOnProcessor = $true and runs the processor timers itself — while cippkvupn-proc (which has CIPP_PROCESSOR=true) also still runs them. Both apps then dispatch the same background timers against every live tenant simultaneously.

That makes "these two apps are on the same build" a correctness requirement, not a nice-to-have.

How

One job, one checkout, two deploy steps — not a matrix and not a second build.

The existing workflow has no build phase at all: package: '.' hands the checked-out repo root straight to Azure/functions-action. So the strongest available guarantee is to reuse the same working directory rather than re-checking-out. A matrix would re-clone the same SHA into a second runner — almost certainly identical, but it reintroduces a "two independent packaging operations" step that this approach removes entirely.

Ordering is deliberate:

  • cippkvupn deploys first, unchanged, and still runs first. A failure in the newly-added proc step cannot prevent production from deploying.
  • The proc step is not if: always(). If the main deploy fails, the proc deploy is skipped, so both apps stay together on the previous version — still in lockstep.

Action ref is pinned to Azure/functions-action@c5060b3b8bb1ebbcb531abd00c822ecbaa8ea656 # v1.5.7 — the same SHA already in use for the main app, per the convention set in "ci: pin our deploy workflow's action refs" (#3). CRLF line endings preserved, same as that PR.

Auth

Publish profile, matching the existing mechanism for this app (this workflow does not use OIDC; only the upstream dev_api.yml does).

A new repo secret AZUREAPPSERVICE_PUBLISHPROFILE_CIPPKVUPN_PROC has already been created from az webapp deployment list-publishing-profiles -g cipp -n cippkvupn-proc --xml. SCM basic auth is enabled on the app, so the profile is valid. No Azure resources were modified.

Naming note: the existing secret uses the Azure-portal-generated GUID form (..._96E4A9290D1D4F3DA01D74E0BE6ED0E1). This secret was created by CLI, so there is no portal GUID to inherit; it is named for its app instead, which keeps the AZUREAPPSERVICE_PUBLISHPROFILE_ prefix while staying readable at the point of failure. Happy to rename to a GUID if strict consistency is preferred.

Risk / notes

  • The main app's deploy path is unchanged. The diff only appends a step after it; its step is byte-for-byte identical.
  • Brief skew window per deploy. The two steps are sequential, so for the minute or so between them the apps are on different versions. This is inherent to any non-atomic two-target deploy, and it self-heals as soon as the second step finishes. It is bounded and far shorter than the current state, where the proc app drifts indefinitely.
  • .github/workflows/ is gitignored in this fork (upstream does this so the sync bot leaves fork workflows alone), so this file needs git add -f. Noting it so the next editor is not surprised.
  • Not yet validated by a real run — deliberately. Verifying would mean deploying to production, so this has only been checked by YAML parse and inspection. The first real exercise will be the next merge to master.

🤖 Generated with Claude Code

cippkvupn-proc is the offload (processor) node for cippkvupn, but it had no
CI/CD at all - it was hand-deployed once. CIPP only dispatches timers to an
offload node whose version EXACTLY matches the main app's, so any drift
silently drops the node and makes both apps run the processor timers.

Add a second Azure/functions-action step to the existing deploy job so the
same checkout is pushed to both apps in one run. No second checkout and no
rebuild, so the two apps cannot skew. The existing cippkvupn step is
untouched and still runs first.

Action ref is pinned to the same commit SHA already used for the main app,
per the convention from "ci: pin our deploy workflow's action refs".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robgilbreath
robgilbreath merged commit 5293c3f into master Sep 11, 2026
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