apps sign reads the passphrase from COGNITE_KEY_PASSPHRASE instead of prompting.
Responsibility of the key owner
A signing key identifies a person, not a repository. Whoever can change what your pipeline runs can sign as you. So as the key owner, you vouch for the pipeline: that it’s healthy, that it hasn’t been tampered with, and that changes to it get reviewed. Restricting what can trigger signing is part of setting this up, not an optional hardening step you get to later.Prerequisites
- A working local signing setup, as described in Signing Flows custom apps from the CLI.
- Dev status on the target Cognite Data Fusion (CDF) project.
- A GitHub repository holding the app, with an OAuth client for deployment. See Automated deployment.
- The GitHub CLI, for setting secrets without pasting them into a browser.
Set up the pipeline
Generate a passphrase
- macOS
- Windows
- Linux
Generate a CI/CD key
--no-keychain gives you a key you can move. The private key goes in a file instead of Keychain.When the CLI prompts, enter a key ID (kid), an email, an expiry, and the passphrase you just generated. The command writes the encrypted private key to ~/.cognite-cli/keys/<kid>.key.jwe and the public key to <kid>.pub.pem.Set the kid to a name for this pipeline, such as acme-ci-001. Keep this key separate from your local signing key so that a compromise of the pipeline exposes only the CI/CD key.Register the public key
keys generate shows in the terminal. The link opens a pre-filled form. Choose Open in browser, or pass --copy-link and submit the form later.In the ticket, state that this is a CI/CD key. Most builders already have a local key registered, and without that note the request looks like a duplicate.Store the secrets
gh secret set COGNITE_KEY_PASSPHRASE prompts for the passphrase, which keeps it out of your shell history.Store the deploy client secret named by deploySecretName in app.json the same way:Pin the CLI
package.json and package-lock.json:npx cognite, which uses this install. --save-exact records 1.12.0 rather than ^1.12.0, and the lockfile pins the bytes as well as the version. npm ci checks each tarball against that hash and fails the job on a mismatch. To upgrade the CLI, change the pinned version in a pull request. Dependabot or Renovate can open that pull request.npx @cognite/cli@latest fetches whatever was published most recently.Add the workflow
.github/workflows/sign-and-publish.yml.sign-and-publish.yml
sign-and-publish.yml
- In the pull request, bump
versionTaginapp.json. Merging without a bump redeploys a version that’s already published. - Open the draft deploy on the pull request and check it. Merging to
mainsigns that draft and activates it.
- Pass secrets through
envso they stay out of the generated shell script. - Write the key with
printf '%s'so the bytes stay unchanged. - Remove the key file with
trap, including when signing fails. - Leave
cancel-in-progressset tofalseso two merges cannot sign two versions into the same slot.
github.event.pull_request.head.repo.fork == false.Restrict what can trigger signing
-
In the repository, open Settings > Rules > Rulesets and add a ruleset for
main. Signing runs when a commit reachesmain, so this ruleset is what keeps an unreviewed commit from being signed. -
Require a pull request with at least one approving review. A commit can reach
mainonly after someone approves the pull request. A direct push is blocked. - Turn on Dismiss stale approvals. If someone pushes new commits after an approval, that approval no longer counts. The new commits need a new review.
Confirm the signature
main, check the version:VALID for the kid the pipeline used.Renew the key before it expires
Signing keys are valid for 12 months by default. When the key expires, the pipeline fails. The person who created the key may no longer maintain the repository. Set a shared calendar reminder for nine months before the key expires, so the repository maintainers can renew it. To keep the key longer, ask Cognite in a Zendesk ticket to extend its validity. Cognite usually completes that request quickly.Rotate a key used by a pipeline
Rotate when a key expires or you suspect it’s compromised, and also when someone with access to the repository secrets leaves the team.- Generate a replacement with
keys generate --no-keychain --interactive. - Register the new public key.
- Update the
COGNITE_SIGNING_KEY_JWEandCOGNITE_KEY_PASSPHRASEsecrets and theCOGNITE_SIGNING_KIDvariable. - Ask your Cognite contact to revoke the old key.
Other CI systems
The sample workflow is GitHub Actions. The signing steps are the same on Azure DevOps or another CI system:- Store the encrypted key and its passphrase as secrets.
- Write the key to a temporary file, set
COGNITE_KEY_PASSPHRASE, and runapps signandapps activate. - Limit who can change the pipeline and what can trigger it. Use the controls that system provides.
Troubleshooting
The key is passphrase-encrypted, but no passphrase was supplied
The key is passphrase-encrypted, but no passphrase was supplied
COGNITE_KEY_PASSPHRASE is set on the step that runs apps sign, and that the secret has a value. A blank value counts as unset. Secrets aren’t passed to workflows triggered from forks, so a run from a fork sees an empty value.The job fails with decryption operation failed
The job fails with decryption operation failed
COGNITE_SIGNING_KEY_JWE and COGNITE_KEY_PASSPHRASE come from the same keys generate run. Rotating one without the other is the usual cause. Verify the pair locally before updating the secrets:Invalid passphrase: must be at least 15 characters
Invalid passphrase: must be at least 15 characters
The passphrase prompt appears and the job hangs
The passphrase prompt appears and the job hangs
apps sign --interactive prompts for the passphrase and ignores COGNITE_KEY_PASSPHRASE. Drop --interactive from the pipeline.apps sign fails with 403: signing key is not in the public key registry
apps sign fails with 403: signing key is not in the public key registry
kid yet. The second sentence is a generic message the CLI shows for any 403. It is not an access problem.Confirm with your Cognite representative that the CI/CD key has been added, then re-run the job. Each run starts without the .dev.sig file that apps sign writes before it sends the signature, so the new run signs the bundle and activates it again. See 403: signing key is not in the public key registry.