Foreman›Docs›Salesforce pack›Set up on Salesforce

Set up on Salesforce

Salesforce pack · page 2 of 9

The questions /foreman:init asks, the org sign-in with Foreman's key, and the Salesforce set-up steps.

Foreman 0.11.05 sections

Preview. The Salesforce pack ships in Foreman 0.11.0 as a preview: its release paths pass their own tests, but no story has yet shipped through them on a live org. Treat the Gearset path as experimental.

This page takes a Salesforce project from nothing to a run: the questions /foreman:init asks and what each answer writes, the key Foreman signs in with, the External Client App you make in each sandbox, connecting each org, and the Salesforce steps on the dashboard’s Set up tab. Read it when you first put Foreman on a Salesforce project; Set up tab covers the steps every project has. The Salesforce pack is a preview: its release paths pass their own tests, but no story has yet shipped through them on a live org, and the Gearset path has not run against a live Gearset pipeline.

The Set up tab gets a Salesforce area with five steps: Salesforce CLI (sf-tools), Salesforce environments (sf-layout), Salesforce org sign-in (sf-orgs), Salesforce skills (sf-skills) and, only when the release path is gearset, Gearset (sf-gearset). Each has a Test it button that runs its doctor checks. With no browser, foreman setup next gives the steps in turn, and foreman setup steps --step sf-orgs --json prints one step’s words.

What /foreman:init asks

On a project with sfdx-project.json at the root, /foreman:init starts with what it found: the package folders and which is the default, sourceApiVersion, the LWC tools (Jest, ESLint, Prettier), and whether OmniStudio or Agentforce metadata is in the source. If sfdx-project.json is broken it says so and carries on. Then it asks the pack’s questions, one at a time, in this order. It never asks for a password, key or token, and never connects to an org.

Question What it asks What it writes
1. Sandboxes The alias and org ID of each sandbox Foreman may use. The org ID is in Setup › Company Information, or in sf org display; it starts with 00D and is 15 or 18 letters and digits. An alias is letters, digits, ., _, @ or -, does not start with -, and may not be prod or production. Two aliases may not share an org ID (the first 15 characters are compared) salesforce.orgs: { "<alias>": { "orgId": "..." } }
2. Branches One branch, or environment branches such as qa and uat? With one branch, which one (default main) baseBranch, left out for main; nothing for environment branches
3. Production deploys Single-branch layout only: “Does anything deploy <branch> to production: a CI job, Gearset or another tool?” A yes means every merge would reach production, so init explains that this layout needs environment branches and asks question 2 again. If you still want one branch, init stops without writing anything nothing
4. Build sandboxes Which sandboxes build stories. A build sandbox that also takes releases means one story at a time and that one sandbox only salesforce.build: one alias as a string, else a list
5. Release stages One to four stages in release order, each with a name (a lowercase letter, then up to 15 lowercase letters or digits), an org from question 1 and, with environment branches only, a branch (default: the stage name). Refused: a stage named prod or production, a name used twice, two stages on one org, a build sandbox on any stage but the first, and a build sandbox as the first stage while more than one sandbox builds. Every sandbox from question 1 must build or be a stage’s org; for one that is neither, init asks whether to use it or drop it salesforce.stages: [{ "name", "org", "branch" }], branch left out in the single-branch layout
6. Production branch Environment-branch layout only, and required there: the branch that holds what is in production (default main). It must not be any stage’s branch salesforce.productionBranch; never written in the single-branch layout
7. Release path sf (Foreman deploys), ci (your CI deploys after the merge and Foreman watches it) or gearset (Gearset promotes the environment branches; offered only with environment branches and no stage on a build sandbox). DevOps Center is not supported yet salesforce.release, left out for sf
8. Where to stop Only with more than one stage: the last stage a story goes to (default: the last). Production is never offered salesforce.stopAt, left out for the last stage

From the general questions init asks only the project’s name and the story source (its folder, or its Jira site and filter). It skips the check command and the CI jobs, because the pack sets the checks, the install step, the ship steps and the pull request target from the release path, and every check on the pull request must pass. It sets slots to the number of build sandboxes (1 when the first stage shares a build sandbox) and leaves it out when it is 1. It never asks about or writes salesforce.test: the default, build, is right. It also leaves out ship, checks, install and roles, because the pack fills them and a ship of your own would replace the pack’s as a whole.

For Acme, with environment branches, one build sandbox and QA then UAT, init writes:

{
  "version": 1,
  "project": { "name": "acme" },
  "pack": "salesforce",
  "stories": { "adapter": "markdown", "dir": "stories" },
  "salesforce": {
    "productionBranch": "main",
    "orgs": {
      "acme-dev1": { "orgId": "00D000000000001" },
      "acme-qa": { "orgId": "00D000000000002" },
      "acme-uat": { "orgId": "00D000000000003" }
    },
    "build": "acme-dev1",
    "stages": [
      { "name": "qa", "org": "acme-qa", "branch": "qa" },
      { "name": "uat", "org": "acme-uat", "branch": "uat" }
    ]
  }
}

After the write, init adds no traits (the pack brings its own for every agent, the security reviewer and the tester), runs foreman sf skills and tells you to commit skills-lock.json, .agents/skills and .claude/skills, and hands off to the Set up tab for the org sign-in. It never runs sf org login itself. foreman doctor then checks that each org is signed in, is a sandbox and has the configured org ID.

Make the key and connect each org

The Salesforce org sign-in step (sf-orgs) is where each org in salesforce.orgs is signed in to Foreman’s own sf home, so story sessions see only those sandboxes and never your other orgs. What the pack adds explains that home. Keys and sign-ins work only on a dashboard that listens on this computer alone; from another machine, open it through an SSH tunnel.

Foreman’s key and certificate

Foreman signs in with the JWT bearer flow, so it needs an RSA key pair. The screen starts with the key card: “No key yet. Make one here, or upload a key and certificate you already have. The key stays on this computer.”

  • Make the key runs openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 730, with the subject Foreman <project id>. The certificate is valid for two years.
  • Upload the key and certificate takes a key file (PEM, no passphrase) and a certificate file (PEM). Foreman refuses a key with a passphrase (take it off with openssl rsa -in <key file> -out <new file>), a key it cannot read, a key that is not RSA, a certificate it cannot read, a certificate not made from that key, and an expired certificate. Only the certificate as Foreman parsed it is saved, so a key pasted into the certificate field by mistake is never served back.
  • Download the certificate gives foreman.crt, the file you upload to the app in each sandbox.
  • Replace the key warns first: the new certificate must be uploaded to the app in every org, and each org connected again.

The pair lives at ~/.config/foreman/sf/<project id>/server.key and server.crt, where the project id is the slug of project.name, a dash, and 8 hex characters of a hash of the project’s real path. It is never inside the repo, an env file or a worktree. The folder and its parent are mode 700, both files mode 600, and each is written under a temporary name and renamed into place. The key never comes back to the page; the card shows the certificate’s fingerprint and expiry. Story sessions are denied the Read tool on ~/.config/foreman/sf, and the Bash guard denies a command that names the folder.

The External Client App

Below the key card, numbered steps walk you through the app Foreman signs in with. You do this once per sandbox:

  1. In the sandbox’s Setup, under Apps › External Client Apps › External Client App Manager, make a New External Client App named Foreman, with your email as its contact and Distribution State Local.
  2. Turn on OAuth. Set the callback URL to the one the screen shows: Salesforce needs one, Foreman does not use it. Add the scopes Manage user data via APIs (api) and Perform requests at any time (refresh_token, offline_access). Under Flow Enablement, tick Enable JWT Bearer Flow and upload the certificate you downloaded, then press Create.
  3. Press Edit and open the Policies tab. Under OAuth Policies, in Plugin Policies, set Permitted Users to “Admin approved users are pre-authorized” and press OK. Under App Policies, add the profile or permission set of the user Foreman signs in as, then Save.
  4. Open the app’s Settings tab, then OAuth Settings, and press Consumer Key and Secret. Salesforce emails you a code to confirm it is you. Copy the Consumer Key only: Foreman does not need the secret.

Connect an org

Each org in salesforce.orgs gets its own row, in the doctor’s order (the build orgs, each stage’s org, then the rest), with its roles (“Used for build”, “Used for stage qa”) or “Not used by any step yet”. The scratch Dev Hub is not listed. Press Connect an org and give:

  • the alias, from the config;
  • the username Foreman signs in as (it looks like an email address, no spaces);
  • the consumer key, copied whole from the app;
  • the login URL, https://test.salesforce.com by default. Leave it for a sandbox, or give the sandbox’s own My Domain address. It must be https:// and a salesforce.com or force.com host, nothing more.

Foreman runs sf org login jwt into the isolated home (“Signing in… sf can take up to 2 minutes”), then asks the org SELECT Id, IsSandbox FROM Organization. The outcomes:

Outcome What happened What to do
Connected The org is a sandbox with the configured org ID. The row shows “Connected to org <org ID>” Press Test it to run the org checks
Org ID differs The org is a sandbox, but its ID is not the one in salesforce.orgs. It stays signed in, and the isolation check keeps runs refused until the ID is fixed Press Save the new org ID to write it into salesforce.orgs.<alias>.orgId, or fix the config
Refused: production The org is not a sandbox and salesforce.orgs does not mark it "production": true with that org ID. Foreman signed it out again at once Connect a sandbox, or mark the org as production if you mean to connect it without deploying
Refused: not checked Foreman could not tell whether the org is a sandbox, so it signed it out Check that the user can use the API, then try again
Failed Sign-in failed; Foreman names the cause and the step that fixes it (see below) Follow the step it points to

A production org the config marks "production": true, with the same org ID, stays connected: deployments to it are never possible. See Production stays yours.

The failure causes, each with the step it points you to:

Cause What Salesforce said What to fix
Not approved the user is not approved for the app Policies: Permitted Users and the user’s profile or permission set
Consumer key it does not know that consumer key Copy the whole key again; a new app can take a few minutes before it works
Login URL it refused the login URL for this org Use https://test.salesforce.com or the sandbox’s own My Domain address
Certificate it could not check the sign-in against the app’s certificate Upload the certificate Foreman shows to the app
Login rate it is limiting sign-ins for this user Foreman will not try that org again for an hour; retrying sooner can lock the user out
Cooling down a login-rate limit was hit a short while ago Wait until the time Foreman gives
Timeout, unreachable sf took too long, or Salesforce could not be reached Try again; check the login URL and the network
No sf the Salesforce CLI is not on PATH Install it (the Salesforce CLI step)
Home FOREMAN_SF_HOME is not an absolute path or cannot be created Set it to an absolute path; ~ is not expanded
Sign-in any other sf error, named by its error name Check the username, the consumer key and the app

No answer carries the key, the username, the consumer key or sf’s own message. You can also sign an org in by hand, into the same home, with the line the step prints: sf org login jwt with HOME set to the isolated home, SF_USE_GENERIC_UNIX_KEYCHAIN=true, the alias from the config, the username, the key file, the consumer key and the login URL.

Source tracking

Build sandboxes need source tracking, so the builder’s changes can be told from what was already in the org. Once, in the production org, which you open yourself (Foreman never connects to it), turn on Setup › Dev Hub › Enable Source Tracking in Developer and Developer Pro Sandboxes, then refresh each build sandbox. Or turn it on in one sandbox alone, with no refresh, in that sandbox’s Sandbox Settings. This is a step you do only in Salesforce, so the screen shows whether its doctor check, salesforce source tracking <alias>, passes once you press Test it. Stage-only orgs are not checked.

Tools, layout and test level

Salesforce CLI (sf-tools) has no inputs; its Test it runs three checks. salesforce tools reads sf plugins --core and wants @salesforce/cli 2.0.0 or newer, sfdx-git-delta 6.0.0 or newer and @salesforce/plugin-code-analyzer 5.0.0 or newer. salesforce plugin warns when the salesforce-development Claude Code plugin is on for you, and tells you there is nothing to do: Foreman turns it off for its own runs. salesforce telemetry is described below.

Salesforce environments (sf-layout) shows two config cards, salesforce.orgs and salesforce.stages, and runs five checks:

Check What it needs
salesforce layout A block that passes the config check. The detail says where each step runs: the build orgs, the test org, each stage’s org and branch, the slots, a stage org that is also a build org (shared), and each production org (connected, deployments blocked, data changes not blocked). It runs no sf and no git
salesforce test level Reads only the saved baselines (see Build orgs). Warns when testLevel.deploy (on the sf path, each stage’s org) or testLevel.validate (stage 1’s org) is RunLocalTests or RunAllTestsInOrg on an org whose baseline cannot pass it
salesforce production branch No pull request and no stage’s own branch merges into it, and it exists on the remote. Unset passes as “none set”, unless a stage has its own branch or the release is gearset
salesforce workflows No file in .github/workflows that runs on push to the pull request target or a stage branch deploys to an org not in salesforce.orgs, or to a target Foreman cannot read. It reads files only
salesforce CONFIRM_PROD Described below

The step’s guide says what to do: list each sandbox under salesforce.orgs by alias and org ID, then name the build sandboxes and the release stages; set salesforce.productionBranch to the branch that deploys to production, which Foreman never merges into; and, to release through Gearset, set salesforce.release to "gearset", give the last stage a sandbox and a branch of its own, and set salesforce.productionBranch. The Gearset step then appears. Every key is in The salesforce block.

The Gearset screen

The Gearset step (sf-gearset) appears only with salesforce.release: "gearset". Its key card takes GEARSET_API_TOKEN, saved to .env.foreman; make the token in Gearset under My account › Team security › Access token management. The Reporting API Foreman uses needs Gearset’s Teams or Enterprise tier, and the screen says so when Gearset answers 403.

Press Read the pipelines. The screen lists the pipelines the token’s team can see; pick the one that promotes this repo and press Save the pipeline. Foreman writes it to foreman.config.json as salesforce.gearset.pipelineId and from then on looks only in that pipeline; without one it looks through every pipeline the token sees. A table then shows each of the pipeline’s environments with columns Gearset environment, Gearset stage, Org, Foreman stage and CI job: the org is the alias in salesforce.orgs with the same org ID, the Foreman stage the one on that org, and the CI job On, Turned off or No CI job. It flags an environment no org matches, Gearset’s production environment (Foreman never promotes there), and each stage no environment deploys to.

Each stage also shows whether its CI job runs Apex tests. Gearset’s API cannot show a CI job’s test level, so Foreman reads Gearset’s newest successful deploy to the stage in the last 30 days and the deploy’s record in the stage’s org. When that shows tests, the screen says how many ran; when it shows none, it tells you to set a test level on the CI job; when no recent deploy shows it either, you check the CI job in Gearset and press “I set a test level on this CI job”. Foreman remembers that as your confirmation, with the date, apart from what it checked, and checks again after Gearset’s next deploy. Undo takes it back.

Its checks: salesforce gearset token (the variable is set in the environment, .env.foreman or the env file; its value is never shown), salesforce gearset branch (ship.merge.keepBranch is on, which the pack sets), salesforce gearset merge method (ship.pr.mergeMethod is merge), salesforce gearset environments (each stage’s org is the target of a Gearset environment that is not production), salesforce gearset ci job (that environment has a CI job that is not turned off) and salesforce gearset ci tests (which only warns). A rate limit or no answer from Gearset warns rather than fails.

Skills

The Salesforce skills step (sf-skills) has one button, Install the skills, which runs foreman sf skills, and reminds you to commit skills-lock.json, .agents/skills and .claude/skills. Its two checks are salesforce skills lock and salesforce skills named. What the pack adds says what the command installs and how the lock works.

CONFIRM_PROD and telemetry

Two checks guard against a project that quietly confirms a production deploy or sends telemetry.

salesforce CONFIRM_PROD, on the Salesforce environments step, fails when CONFIRM_PROD is set in the environment or the project’s env file, or when any check’s run or quick command contains CONFIRM_PROD or --I-CONFIRM-PROD. Foreman never sets or passes either; remove it wherever it is.

salesforce telemetry, on the Salesforce CLI step, runs sf config get disable-telemetry as you and warns when the CLI still sends telemetry. Set SF_DISABLE_TELEMETRY=true in the project’s env file (.env.local unless envFile says otherwise), or run sf config set disable-telemetry true --global. Story sessions get SF_DISABLE_TELEMETRY=true from the sf wrapper whatever you do; this check is about your own sf.