Skip to content

Commit 80d594f

Browse files
authored
docs(ci-cd): document staging mTLS deployments via GitHub Actions (#431)
* docs(ci-cd): document staging mTLS deployments via GitHub Actions Add a Staging Environments section to the CI/CD guide covering the two-factor mTLS pattern (separate webdav hostname + .p12 client cert) in both CLI flag and GitHub Actions form. Extend the setup action with webdav-server, certificate, certificate-passphrase, and selfsigned inputs so workflows can target staging without bespoke env wiring. Cross-link with the existing mTLS section in the configuration guide. * fix: tighten selfsigned env handling and correct setup re-run note - setup action: only export SFCC_SELFSIGNED when input is "true"/"1". oclif boolean env-mapped flags treat any non-empty value as true, while the SDK env-var source only parses "true"/"1" — exporting arbitrary values produced inconsistent behavior. Now omitting the input (or passing "false") cleanly leaves the flag at its default. - ci-cd.md: correct misleading tip claiming a second setup overwrites env vars; in fact it only overrides env vars for inputs that are actually re-passed (others persist from the prior setup). * docs(ci-cd): use real SFCC_* env var names in staging example The staging mTLS section invented SFCC_STAGING_* secret/variable names that looked like tooling env vars but are not read by anything. Rename them to the actual SFCC_* names the tooling consumes (matching the Authentication section convention) and keep only the base64 cert blob under a plainly non-SFCC name, making clear it is decoded to a file rather than read as an env var.
1 parent de8d40b commit 80d594f

5 files changed

Lines changed: 183 additions & 0 deletions

File tree

.changeset/staging-ci-cd-docs.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@salesforce/b2c-dx-docs': patch
3+
---
4+
5+
Document deploying to staging environments (two-factor mTLS) from CI/CD. The `setup` GitHub Action now accepts `webdav-server`, `certificate`, `certificate-passphrase`, and `selfsigned` inputs so workflows can target staging instances that require a separate WebDAV hostname and a client certificate. The CI/CD guide includes a full GitHub Actions example using a base64-encoded `.p12` secret.

actions/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ All actions accept auth inputs directly or read from `SFCC_*` environment variab
100100
| `mrt-project` | `MRT_PROJECT` | MRT operations |
101101
| `mrt-environment` | `MRT_ENVIRONMENT` | MRT operations |
102102
| `account-manager-host` | `SFCC_ACCOUNT_MANAGER_HOST` | Account Manager |
103+
| `webdav-server` | `SFCC_WEBDAV_SERVER` | Staging WebDAV (cert. hostname) |
104+
| `certificate` | `SFCC_CERTIFICATE` | Two-factor mTLS (PKCS12 path) |
105+
| `certificate-passphrase` | `SFCC_CERTIFICATE_PASSPHRASE` | Two-factor mTLS |
106+
| `selfsigned` | `SFCC_SELFSIGNED` | Allow self-signed server certs |
107+
108+
For staging environments that require a separate WebDAV hostname and a client certificate, see the [Staging Environments guide](https://salesforcecommercecloud.github.io/b2c-developer-tooling/guide/ci-cd.html#staging-environments-two-factor-mtls) for the full pattern (decoding a base64-encoded `.p12` from a secret + wiring it through `setup`).
103109

104110
## Plugins
105111

actions/setup/action.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ inputs:
5353
account-manager-host:
5454
description: 'Account Manager hostname → SFCC_ACCOUNT_MANAGER_HOST'
5555
required: false
56+
webdav-server:
57+
description: 'Separate WebDAV hostname (used for staging cert. hostnames) → SFCC_WEBDAV_SERVER'
58+
required: false
59+
certificate:
60+
description: 'Path to PKCS12 client certificate for two-factor (mTLS) auth → SFCC_CERTIFICATE'
61+
required: false
62+
certificate-passphrase:
63+
description: 'Passphrase for the PKCS12 client certificate → SFCC_CERTIFICATE_PASSPHRASE'
64+
required: false
65+
selfsigned:
66+
description: 'Allow self-signed server certificates → SFCC_SELFSIGNED. Set to "true" to enable; omit otherwise.'
67+
required: false
5668
log-level:
5769
description: 'CLI log level (trace, debug, info, warn, error, silent) → SFCC_LOG_LEVEL'
5870
required: false
@@ -147,6 +159,22 @@ runs:
147159
if [ -n "${{ inputs.account-manager-host }}" ]; then
148160
echo "SFCC_ACCOUNT_MANAGER_HOST=${{ inputs.account-manager-host }}" >> "$GITHUB_ENV"
149161
fi
162+
if [ -n "${{ inputs.webdav-server }}" ]; then
163+
echo "SFCC_WEBDAV_SERVER=${{ inputs.webdav-server }}" >> "$GITHUB_ENV"
164+
fi
165+
if [ -n "${{ inputs.certificate }}" ]; then
166+
echo "SFCC_CERTIFICATE=${{ inputs.certificate }}" >> "$GITHUB_ENV"
167+
fi
168+
if [ -n "${{ inputs.certificate-passphrase }}" ]; then
169+
echo "SFCC_CERTIFICATE_PASSPHRASE=${{ inputs.certificate-passphrase }}" >> "$GITHUB_ENV"
170+
fi
171+
# Only export SFCC_SELFSIGNED when explicitly truthy. The SDK's env-var
172+
# source treats only "true"/"1" as enabling self-signed mode, but oclif
173+
# boolean flags map any non-empty env value to true. Skipping export for
174+
# other values avoids that asymmetry — leaving the flag at its default.
175+
if [ "${{ inputs.selfsigned }}" = "true" ] || [ "${{ inputs.selfsigned }}" = "1" ]; then
176+
echo "SFCC_SELFSIGNED=true" >> "$GITHUB_ENV"
177+
fi
150178
if [ -n "${{ inputs.log-level }}" ]; then
151179
echo "SFCC_LOG_LEVEL=${{ inputs.log-level }}" >> "$GITHUB_ENV"
152180
fi

docs/guide/ci-cd.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,30 @@ Installs the CLI and writes credentials to environment variables. Use this when
129129

130130
Plugins are installed after the CLI; already-installed plugins are skipped by exact name match. Each line is an npm package name or GitHub `owner/repo`. For reliable skip-on-reinstall, prefer the published npm package name — when a GitHub `owner/repo` slug differs from the package it publishes, the plugin is reinstalled each run (harmless, just slower).
131131

132+
The setup action accepts the following inputs (each maps to the corresponding `SFCC_*` environment variable):
133+
134+
| Input | Environment Variable |
135+
|-------|---------------------|
136+
| `client-id` | `SFCC_CLIENT_ID` |
137+
| `client-secret` | `SFCC_CLIENT_SECRET` |
138+
| `server` | `SFCC_SERVER` |
139+
| `code-version` | `SFCC_CODE_VERSION` |
140+
| `username` | `SFCC_USERNAME` |
141+
| `password` | `SFCC_PASSWORD` |
142+
| `short-code` | `SFCC_SHORTCODE` |
143+
| `tenant-id` | `SFCC_TENANT_ID` |
144+
| `account-manager-host` | `SFCC_ACCOUNT_MANAGER_HOST` |
145+
| `webdav-server` | `SFCC_WEBDAV_SERVER` |
146+
| `certificate` | `SFCC_CERTIFICATE` |
147+
| `certificate-passphrase` | `SFCC_CERTIFICATE_PASSPHRASE` |
148+
| `selfsigned` | `SFCC_SELFSIGNED` |
149+
| `mrt-api-key` | `MRT_API_KEY` |
150+
| `mrt-project` | `MRT_PROJECT` |
151+
| `mrt-environment` | `MRT_ENVIRONMENT` |
152+
| `log-level` | `SFCC_LOG_LEVEL` |
153+
154+
The `webdav-server`, `certificate`, `certificate-passphrase`, and `selfsigned` inputs are only needed for staging environments that require a separate WebDAV hostname and a client certificate (mTLS). See [Staging Environments (Two-Factor mTLS)](#staging-environments-two-factor-mtls).
155+
132156
### Run
133157

134158
```
@@ -281,6 +305,120 @@ Upload files via WebDAV.
281305
| `remote-path` | *(required)* | Remote destination path |
282306
| `root` | `IMPEX` | WebDAV root (IMPEX, TEMP, CARTRIDGES, etc.) |
283307

308+
## Staging Environments (Two-Factor mTLS)
309+
310+
Internal staging instances typically require:
311+
312+
- A separate WebDAV hostname (often a `cert.*` variant of the main hostname)
313+
- A PKCS12 (`.p12`) client certificate with passphrase for mutual TLS
314+
- Permission to accept self-signed server certificates
315+
316+
See [Two-Factor Authentication (mTLS)](/guide/configuration#two-factor-authentication-mtls) for the underlying configuration model.
317+
318+
### CLI Flags
319+
320+
The same options that go in `dw.json` are available as CLI flags. For local use against a staging instance:
321+
322+
```bash
323+
b2c code deploy \
324+
--server staging-internal-ccdemo.demandware.net \
325+
--webdav-server cert.staging.internal.ccdemo.demandware.net \
326+
--certificate /path/to/STG-2FA-ccdemo/deploy.p12 \
327+
--passphrase 'your-cert-passphrase' \
328+
--selfsigned \
329+
--client-id "$SFCC_CLIENT_ID" \
330+
--client-secret "$SFCC_CLIENT_SECRET"
331+
```
332+
333+
| Flag | dw.json Field | Environment Variable |
334+
|------|---------------|---------------------|
335+
| `--server` | `hostname` | `SFCC_SERVER` |
336+
| `--webdav-server` | `webdav-hostname` | `SFCC_WEBDAV_SERVER` |
337+
| `--certificate` | `certificate` | `SFCC_CERTIFICATE` |
338+
| `--passphrase` | `certificate-passphrase` | `SFCC_CERTIFICATE_PASSPHRASE` |
339+
| `--selfsigned` | `self-signed` | `SFCC_SELFSIGNED` |
340+
341+
### GitHub Actions
342+
343+
Staging mTLS works with the standard actions — the `setup` action accepts `webdav-server`, `certificate`, `certificate-passphrase`, and `selfsigned` inputs alongside the usual auth inputs.
344+
345+
Because the `.p12` is a binary file, store it as a base64-encoded GitHub secret and decode it to disk in a workflow step before calling `setup`. The `certificate` input then points at the decoded path.
346+
347+
These are in addition to the [authentication](#authentication) secrets and variables — the same `SFCC_*` names used elsewhere map straight through to the `setup` inputs:
348+
349+
| Secret | Maps to input → env var | Description |
350+
|--------|-------------------------|-------------|
351+
| `SFCC_CLIENT_ID` | `client-id``SFCC_CLIENT_ID` | OAuth Client ID |
352+
| `SFCC_CLIENT_SECRET` | `client-secret``SFCC_CLIENT_SECRET` | OAuth Client Secret |
353+
| `SFCC_CERTIFICATE_PASSPHRASE` | `certificate-passphrase``SFCC_CERTIFICATE_PASSPHRASE` | Passphrase for the `.p12` |
354+
| `STAGING_CERTIFICATE_P12_BASE64` | *(none — decoded to a file)* | Base64-encoded `.p12` client certificate |
355+
356+
| Variable | Maps to input → env var | Description |
357+
|----------|-------------------------|-------------|
358+
| `SFCC_SERVER` | `server``SFCC_SERVER` | e.g. `staging-internal-ccdemo.demandware.net` |
359+
| `SFCC_WEBDAV_SERVER` | `webdav-server``SFCC_WEBDAV_SERVER` | e.g. `cert.staging.internal.ccdemo.demandware.net` |
360+
361+
`STAGING_CERTIFICATE_P12_BASE64` is the only value here that is **not** an `SFCC_*` environment variable — it holds the raw base64 of the certificate file, which a workflow step decodes to disk. The `certificate` input then points at that decoded path (the tooling reads the file path from `SFCC_CERTIFICATE`, not the certificate contents).
362+
363+
To create the base64 secret locally:
364+
365+
```bash
366+
base64 -i deploy.p12 | pbcopy # macOS
367+
# or
368+
base64 -w0 deploy.p12 # Linux
369+
```
370+
371+
Then paste the value into a GitHub repository secret.
372+
373+
**Workflow example:**
374+
375+
```yaml
376+
name: Deploy to Staging
377+
378+
on:
379+
workflow_dispatch:
380+
381+
jobs:
382+
deploy:
383+
runs-on: ubuntu-latest
384+
steps:
385+
- uses: actions/checkout@v4
386+
387+
# Decode the .p12 to a file inside the runner workspace
388+
- name: Decode staging client certificate
389+
run: |
390+
echo "${{ secrets.STAGING_CERTIFICATE_P12_BASE64 }}" \
391+
| base64 --decode > "$RUNNER_TEMP/staging-deploy.p12"
392+
chmod 600 "$RUNNER_TEMP/staging-deploy.p12"
393+
394+
- uses: SalesforceCommerceCloud/b2c-developer-tooling/actions/setup@v1
395+
with:
396+
client-id: ${{ secrets.SFCC_CLIENT_ID }}
397+
client-secret: ${{ secrets.SFCC_CLIENT_SECRET }}
398+
server: ${{ vars.SFCC_SERVER }}
399+
webdav-server: ${{ vars.SFCC_WEBDAV_SERVER }}
400+
certificate: ${{ runner.temp }}/staging-deploy.p12
401+
certificate-passphrase: ${{ secrets.SFCC_CERTIFICATE_PASSPHRASE }}
402+
selfsigned: 'true'
403+
404+
- run: npm ci && npm run build
405+
406+
- uses: SalesforceCommerceCloud/b2c-developer-tooling/actions/code-deploy@v1
407+
with:
408+
code-version: staging-${{ github.run_number }}
409+
activate: true
410+
```
411+
412+
Once the `setup` step writes `SFCC_CERTIFICATE`, `SFCC_WEBDAV_SERVER`, etc. to `$GITHUB_ENV`, every subsequent action picks them up automatically — no need to repeat them on `code-deploy`, `data-import`, `job-run`, or `webdav-upload`.
413+
414+
::: tip Multiple Environments in One Workflow
415+
If a single workflow targets both a normal sandbox and a staging instance, run `setup` again before each phase with the appropriate inputs. The second `setup` only overrides env vars for inputs you actually pass — anything left blank keeps its value from the previous `setup`. To fully switch environments, re-pass every variable that should change (or use the `env:` block on individual steps to scope overrides).
416+
:::
417+
418+
::: warning Cleanup
419+
The decoded `.p12` lives only inside the runner's ephemeral workspace and is destroyed when the job ends. Never commit the file or write it outside `$RUNNER_TEMP` / the workspace.
420+
:::
421+
284422
## Patterns
285423

286424
### Data Import Pipeline

docs/guide/configuration.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,12 @@ For instances that require client certificate authentication:
290290

291291
The certificate must be in PKCS12 format (`.p12` or `.pfx`). The `self-signed` option is often needed for staging environments with internal certificates.
292292

293+
The same fields are available as CLI flags (`--webdav-server`, `--certificate`, `--passphrase`, `--selfsigned`) and as environment variables (`SFCC_WEBDAV_SERVER`, `SFCC_CERTIFICATE`, `SFCC_CERTIFICATE_PASSPHRASE`, `SFCC_SELFSIGNED`).
294+
295+
::: tip Running staging deploys in CI/CD
296+
For GitHub Actions workflows that target staging — including how to handle the `.p12` certificate as a base64-encoded secret — see [Staging Environments (Two-Factor mTLS)](/guide/ci-cd#staging-environments-two-factor-mtls).
297+
:::
298+
293299
::: tip MRT Configuration
294300
MRT API key can also be loaded from `~/.mobify`. See [MRT API Key](#mrt-api-key) below.
295301
:::

0 commit comments

Comments
 (0)