diff --git a/.changeset/staging-ci-cd-docs.md b/.changeset/staging-ci-cd-docs.md new file mode 100644 index 00000000..d8316570 --- /dev/null +++ b/.changeset/staging-ci-cd-docs.md @@ -0,0 +1,5 @@ +--- +'@salesforce/b2c-dx-docs': patch +--- + +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. diff --git a/actions/README.md b/actions/README.md index 5faf2b38..b67ca7b1 100644 --- a/actions/README.md +++ b/actions/README.md @@ -100,6 +100,12 @@ All actions accept auth inputs directly or read from `SFCC_*` environment variab | `mrt-project` | `MRT_PROJECT` | MRT operations | | `mrt-environment` | `MRT_ENVIRONMENT` | MRT operations | | `account-manager-host` | `SFCC_ACCOUNT_MANAGER_HOST` | Account Manager | +| `webdav-server` | `SFCC_WEBDAV_SERVER` | Staging WebDAV (cert. hostname) | +| `certificate` | `SFCC_CERTIFICATE` | Two-factor mTLS (PKCS12 path) | +| `certificate-passphrase` | `SFCC_CERTIFICATE_PASSPHRASE` | Two-factor mTLS | +| `selfsigned` | `SFCC_SELFSIGNED` | Allow self-signed server certs | + +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`). ## Plugins diff --git a/actions/setup/action.yml b/actions/setup/action.yml index e4a9a578..fed2ba99 100644 --- a/actions/setup/action.yml +++ b/actions/setup/action.yml @@ -53,6 +53,18 @@ inputs: account-manager-host: description: 'Account Manager hostname → SFCC_ACCOUNT_MANAGER_HOST' required: false + webdav-server: + description: 'Separate WebDAV hostname (used for staging cert. hostnames) → SFCC_WEBDAV_SERVER' + required: false + certificate: + description: 'Path to PKCS12 client certificate for two-factor (mTLS) auth → SFCC_CERTIFICATE' + required: false + certificate-passphrase: + description: 'Passphrase for the PKCS12 client certificate → SFCC_CERTIFICATE_PASSPHRASE' + required: false + selfsigned: + description: 'Allow self-signed server certificates → SFCC_SELFSIGNED. Set to "true" to enable; omit otherwise.' + required: false log-level: description: 'CLI log level (trace, debug, info, warn, error, silent) → SFCC_LOG_LEVEL' required: false @@ -147,6 +159,22 @@ runs: if [ -n "${{ inputs.account-manager-host }}" ]; then echo "SFCC_ACCOUNT_MANAGER_HOST=${{ inputs.account-manager-host }}" >> "$GITHUB_ENV" fi + if [ -n "${{ inputs.webdav-server }}" ]; then + echo "SFCC_WEBDAV_SERVER=${{ inputs.webdav-server }}" >> "$GITHUB_ENV" + fi + if [ -n "${{ inputs.certificate }}" ]; then + echo "SFCC_CERTIFICATE=${{ inputs.certificate }}" >> "$GITHUB_ENV" + fi + if [ -n "${{ inputs.certificate-passphrase }}" ]; then + echo "SFCC_CERTIFICATE_PASSPHRASE=${{ inputs.certificate-passphrase }}" >> "$GITHUB_ENV" + fi + # Only export SFCC_SELFSIGNED when explicitly truthy. The SDK's env-var + # source treats only "true"/"1" as enabling self-signed mode, but oclif + # boolean flags map any non-empty env value to true. Skipping export for + # other values avoids that asymmetry — leaving the flag at its default. + if [ "${{ inputs.selfsigned }}" = "true" ] || [ "${{ inputs.selfsigned }}" = "1" ]; then + echo "SFCC_SELFSIGNED=true" >> "$GITHUB_ENV" + fi if [ -n "${{ inputs.log-level }}" ]; then echo "SFCC_LOG_LEVEL=${{ inputs.log-level }}" >> "$GITHUB_ENV" fi diff --git a/docs/guide/ci-cd.md b/docs/guide/ci-cd.md index 09ecaf6f..9384e7fb 100644 --- a/docs/guide/ci-cd.md +++ b/docs/guide/ci-cd.md @@ -129,6 +129,30 @@ Installs the CLI and writes credentials to environment variables. Use this when 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). +The setup action accepts the following inputs (each maps to the corresponding `SFCC_*` environment variable): + +| Input | Environment Variable | +|-------|---------------------| +| `client-id` | `SFCC_CLIENT_ID` | +| `client-secret` | `SFCC_CLIENT_SECRET` | +| `server` | `SFCC_SERVER` | +| `code-version` | `SFCC_CODE_VERSION` | +| `username` | `SFCC_USERNAME` | +| `password` | `SFCC_PASSWORD` | +| `short-code` | `SFCC_SHORTCODE` | +| `tenant-id` | `SFCC_TENANT_ID` | +| `account-manager-host` | `SFCC_ACCOUNT_MANAGER_HOST` | +| `webdav-server` | `SFCC_WEBDAV_SERVER` | +| `certificate` | `SFCC_CERTIFICATE` | +| `certificate-passphrase` | `SFCC_CERTIFICATE_PASSPHRASE` | +| `selfsigned` | `SFCC_SELFSIGNED` | +| `mrt-api-key` | `MRT_API_KEY` | +| `mrt-project` | `MRT_PROJECT` | +| `mrt-environment` | `MRT_ENVIRONMENT` | +| `log-level` | `SFCC_LOG_LEVEL` | + +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). + ### Run ``` @@ -281,6 +305,120 @@ Upload files via WebDAV. | `remote-path` | *(required)* | Remote destination path | | `root` | `IMPEX` | WebDAV root (IMPEX, TEMP, CARTRIDGES, etc.) | +## Staging Environments (Two-Factor mTLS) + +Internal staging instances typically require: + +- A separate WebDAV hostname (often a `cert.*` variant of the main hostname) +- A PKCS12 (`.p12`) client certificate with passphrase for mutual TLS +- Permission to accept self-signed server certificates + +See [Two-Factor Authentication (mTLS)](/guide/configuration#two-factor-authentication-mtls) for the underlying configuration model. + +### CLI Flags + +The same options that go in `dw.json` are available as CLI flags. For local use against a staging instance: + +```bash +b2c code deploy \ + --server staging-internal-ccdemo.demandware.net \ + --webdav-server cert.staging.internal.ccdemo.demandware.net \ + --certificate /path/to/STG-2FA-ccdemo/deploy.p12 \ + --passphrase 'your-cert-passphrase' \ + --selfsigned \ + --client-id "$SFCC_CLIENT_ID" \ + --client-secret "$SFCC_CLIENT_SECRET" +``` + +| Flag | dw.json Field | Environment Variable | +|------|---------------|---------------------| +| `--server` | `hostname` | `SFCC_SERVER` | +| `--webdav-server` | `webdav-hostname` | `SFCC_WEBDAV_SERVER` | +| `--certificate` | `certificate` | `SFCC_CERTIFICATE` | +| `--passphrase` | `certificate-passphrase` | `SFCC_CERTIFICATE_PASSPHRASE` | +| `--selfsigned` | `self-signed` | `SFCC_SELFSIGNED` | + +### GitHub Actions + +Staging mTLS works with the standard actions — the `setup` action accepts `webdav-server`, `certificate`, `certificate-passphrase`, and `selfsigned` inputs alongside the usual auth inputs. + +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. + +These are in addition to the [authentication](#authentication) secrets and variables — the same `SFCC_*` names used elsewhere map straight through to the `setup` inputs: + +| Secret | Maps to input → env var | Description | +|--------|-------------------------|-------------| +| `SFCC_CLIENT_ID` | `client-id` → `SFCC_CLIENT_ID` | OAuth Client ID | +| `SFCC_CLIENT_SECRET` | `client-secret` → `SFCC_CLIENT_SECRET` | OAuth Client Secret | +| `SFCC_CERTIFICATE_PASSPHRASE` | `certificate-passphrase` → `SFCC_CERTIFICATE_PASSPHRASE` | Passphrase for the `.p12` | +| `STAGING_CERTIFICATE_P12_BASE64` | *(none — decoded to a file)* | Base64-encoded `.p12` client certificate | + +| Variable | Maps to input → env var | Description | +|----------|-------------------------|-------------| +| `SFCC_SERVER` | `server` → `SFCC_SERVER` | e.g. `staging-internal-ccdemo.demandware.net` | +| `SFCC_WEBDAV_SERVER` | `webdav-server` → `SFCC_WEBDAV_SERVER` | e.g. `cert.staging.internal.ccdemo.demandware.net` | + +`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). + +To create the base64 secret locally: + +```bash +base64 -i deploy.p12 | pbcopy # macOS +# or +base64 -w0 deploy.p12 # Linux +``` + +Then paste the value into a GitHub repository secret. + +**Workflow example:** + +```yaml +name: Deploy to Staging + +on: + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Decode the .p12 to a file inside the runner workspace + - name: Decode staging client certificate + run: | + echo "${{ secrets.STAGING_CERTIFICATE_P12_BASE64 }}" \ + | base64 --decode > "$RUNNER_TEMP/staging-deploy.p12" + chmod 600 "$RUNNER_TEMP/staging-deploy.p12" + + - uses: SalesforceCommerceCloud/b2c-developer-tooling/actions/setup@v1 + with: + client-id: ${{ secrets.SFCC_CLIENT_ID }} + client-secret: ${{ secrets.SFCC_CLIENT_SECRET }} + server: ${{ vars.SFCC_SERVER }} + webdav-server: ${{ vars.SFCC_WEBDAV_SERVER }} + certificate: ${{ runner.temp }}/staging-deploy.p12 + certificate-passphrase: ${{ secrets.SFCC_CERTIFICATE_PASSPHRASE }} + selfsigned: 'true' + + - run: npm ci && npm run build + + - uses: SalesforceCommerceCloud/b2c-developer-tooling/actions/code-deploy@v1 + with: + code-version: staging-${{ github.run_number }} + activate: true +``` + +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`. + +::: tip Multiple Environments in One Workflow +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). +::: + +::: warning Cleanup +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. +::: + ## Patterns ### Data Import Pipeline diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md index d8290348..5695a83d 100644 --- a/docs/guide/configuration.md +++ b/docs/guide/configuration.md @@ -290,6 +290,12 @@ For instances that require client certificate authentication: The certificate must be in PKCS12 format (`.p12` or `.pfx`). The `self-signed` option is often needed for staging environments with internal certificates. +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`). + +::: tip Running staging deploys in CI/CD +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). +::: + ::: tip MRT Configuration MRT API key can also be loaded from `~/.mobify`. See [MRT API Key](#mrt-api-key) below. :::