Federal Modernization Workbook
Chapter 09 — Deploying to Test and Production
A runbook is not a description of a deployment. It is the deployment, written down before it happens, so the second run is the same as the first.
The runbook that takes the kit past the developer instance. Stage 1 deploys it to a ServiceNow sub-production instance and a SailPoint Identity Security Cloud (ISC) sandbox tenant, enables it in stages, smoke-tests it with a synthetic worker and rehearses the rollback. Stage 2 repeats the same commands against the production instance in ServiceNow’s Government Community Cloud and the production ISC tenant, under a change record, and adds the schedules and a week of monitoring. One settings file per environment carries everything that differs; the commands don’t change. New scripts in the kit’s deploy/ folder do the checks, and each step names the gate of the example guide it fulfils.
This chapter has not been run against a live ServiceNow instance or SailPoint tenant, by the authors or anyone else. The scripts in deploy/ were run on November 2, 2026 against the kit’s fictional fixtures, and that output is shown below with its date. Every “expect” in Stage 1 and Stage 2 is what the kit’s code and the vendors’ documentation say should happen, not something anyone has seen happen. Run Stage 1 completely, and keep its evidence, before trusting any step of Stage 2.
Each step, or group of steps, ends with a table: the federal requirement it serves (NIST SP 800-53 Rev. 5 controls at the Moderate baseline, OMB M-22-09 and CISA BOD 25-01 where they apply, and FedRAMP use of the cloud services), what the step does for it, the FedRAMP 20x Key Security Indicator (KSI) it aligns to, and the file or output that proves it. The control for each row comes from the example guide’s per-gate requirement tables and Book 13, Appendix A, and OMB M-22-09 from the memorandum itself; the KSI is one whose “Related SP 800-53 Controls” on FedRAMP’s page include that control.1 KSIs are FedRAMP’s indicators for cloud service providers. The agency authorizes its own system and lines its evidence up with what ServiceNow and SailPoint report against the KSIs; it doesn’t report KSIs itself (Book 00, Appendix B). The scripted steps produce their own evidence: each writes a hash-chained record of the step, its command, its result and the controls and KSIs it supports, and the promotion go/no-go checks that every record for the test stage is present and passing. The mappings are the program’s; the authorizing official and assessors decide whether a control is met.
Goal and audience
Goal. By the end of this chapter you can deploy the kit to a test environment, prove it works with a synthetic worker, roll it back, decide whether it may go to production, and then deploy the same version to production and watch its first week, leaving a folder of evidence at every stage.
Audience. The developer or platform engineer who runs the deployment, the ServiceNow and SailPoint administrators who make the console changes it names, the change manager, and the ISSO who receives the evidence. You should be at ease in a bash shell. You don’t need to understand the kit’s internals: Chapters 01 to 08 explain them, and this chapter only follows them.
Before you start
Roles
| Role | What they do in this runbook | What they hold |
|---|---|---|
| Deployer | Runs every command, keeps the evidence folder, owns the change record | Access to the vault holding the integration secrets; no standing administrator role |
| ServiceNow administrator | Installs the application and sets its system properties | admin on the instance, for the install and the properties23 |
| ServiceNow change manager | Approves the production change record | The agency’s change approver role |
| SailPoint administrator | Turns on Native Change Detection, starts aggregations, creates the API clients | An ISC administrator able to edit sources and API clients4 |
| Workflow tester | Holds the personal access token that test-runs a workflow | An ORG_ADMIN user, because the test endpoint lists only that user level5 |
| Entra user administrator | Creates and edits the synthetic worker’s Entra account where the HR feed doesn’t | User Administrator, the least-privileged role Microsoft lists for those tasks67 |
| ISSO | Accepts each stage’s evidence and the go/no-go decision | — |
Seven integration identities run the kit and these scripts, one per task, as Chapter 02 and Chapter 03 split them. The settings file records each one’s client ID and grant; the secrets stay in the vault. The Graph reader, the app registration with a certificate that the drift and re-read clients use (Chapter 03), is named by the settings file’s GRAPH_* keys and needs no secret in the shell.
| Identity | System | Least privilege (from config/calls.json) |
Used for |
|---|---|---|---|
finding_writer |
ServiceNow | x_example_idkit.finding_writer |
The ISC workflows’ posts; smoke_test.py raise and signal |
verifier |
ServiceNow | x_example_idkit.verifier |
The re-read client |
evidence_reader |
ServiceNow | x_example_idkit.evidence_reader |
The evidence export; pre-flight, smoke checks and rollback checks |
isc_reader |
ISC | sp:search:read, idn:accounts:read |
The drift and re-read clients |
isc_deploy_checker |
ISC | sp:workflow:read |
Pre-flight and rollback: list the workflows |
isc_workflow_admin |
ISC | sp:workflow:manage |
Create, enable and disable the workflows |
isc_workflow_tester |
ISC | sp:workflow-execute:external, sp:workflow-execution:read (a personal access token of an ORG_ADMIN user) |
Test-run a disabled workflow and read the execution |
Approvals
| Before | Who approves | What they approve |
|---|---|---|
| Stage 1 | The system owner and the ISSO | Deploying to the test environment with a synthetic worker; the seven integration identities (design guidance) |
| Stage 2 | The ISSO, then the change manager | The go/no-go criteria met, with Stage 1’s evidence; the production change record |
| The production smoke test | The ISSO | A synthetic worker in production, and synthetic findings in the production record that close on a re-read (design guidance) |
| Any autonomous lane | The authorizing official | As the guide’s Gate 2 requires; this runbook enables none |
The change record
Production needs one; the test stage takes one if the agency’s practice asks for it (design guidance). In the production instance, a person with itil, admin or sn_change_write raises it at All > Change > Create New and chooses Normal; ServiceNow offers Normal, Emergency and Standard.8 A normal change fits a first deployment, because the guide’s lane table gives standard changes only to pre-authorized classes (Gate 2). Record its number in the settings file’s deploy.change_record; the pre-flight check fails in production without it, and the smoke test writes it into each synthetic finding’s origin.
What must already be in place
- The scoped application, built once on the agency’s development instance from the kit README’s ServiceNow setup: the
u_identity_findingtable, the Scripted REST resource, the business rule, the three custom roles and the system properties, as Chapters 01, 02 and 05 build them in a developer instance. Link it to source control in App Engine Studio. - A synthetic worker in each environment (design guidance): a record in the HR source the ISC tenant aggregates, so it has an ISC identity, correlated to an Entra account whose
departmentisSmoke Test, with sign-in disabled. If that environment’s HR feed doesn’t create the Entra account, an Entra user administrator creates it at Entra ID > Users > New user > Create new user, with Account enabled cleared, and sets Department under Job information.9 Record its IDs in the settings file’sdeploy.syntheticblock. - On the deployer’s machine: bash (Git Bash on Windows),
curl, Python 3.10 or later withrequestsand, for the Graph certificate,cryptography; a clone of the repository; the vault.
Placeholders
Every command below is copy-paste. The settings file holds every value that differs between the environments, so the commands themselves have only these placeholders, listed once:
| Placeholder | Where | What to put |
|---|---|---|
The <...> values in deploy/environment.example.json |
Your copies, deploy/environment.test.json and deploy/environment.production.json |
Each environment’s ServiceNow and ISC addresses, its seven client IDs and grants, the workflow owner, the Gate 1 record, the change record and the synthetic worker’s IDs. The pre-flight check fails while any is left |
<hr-extract.csv> |
Stage 2, the schedules | The path of the HR extract the drift reconciliation reads in production |
<grace-hours> |
Stage 2, the schedules | The re-read client’s grace period, tuned to the ISC aggregation schedule (Gate 6, step 4) |
Secrets are never typed into a command: each step prompts for the secret it needs, without echoing it, and you paste it from the vault.
The code: examples/servicenow-sailpoint/deploy
What exists
The kit’s clients, their call list and their tests (Chapters 01 to 08), the three ISC workflows in one file that posts to an example instance, and a README that says what to set up by hand. The guide gives the seven gates and a rollback per gate in prose. Nothing turned those into steps a deployer could run twice and get the same result.
What this chapter adds
| File | What it does | Runs as |
|---|---|---|
deploy/environment.example.json |
The settings template: the kit’s own config keys plus a deploy block. Placeholders only; the kit’s loader refuses a secret key in it |
— |
deploy/preflight.py |
The settings file, Gate 1 (the Marketplace record, read within 30 days, and SailPoint’s written feature confirmation, a FAIL in production), OAuth or a vault token rather than basic authentication, the change record, every identity’s grant against config/calls.json, an endpoint variable that would override the file, then the finding table and the workflows’ state and failure counts. Exits 1 on any FAIL |
evidence_reader, isc_deploy_checker |
deploy/render_workflows.py |
One of the three workflows with this environment’s ServiceNow URL, owner and client ID, disabled; the secret only from an environment variable, to standard output; and a test input for each workflow built on the synthetic worker | — (reads files) |
deploy/smoke_test.py |
raise: the synthetic finding posted twice; signal: a closure signal; check: one synthetic finding read back and its state compared |
finding_writer; evidence_reader for check |
deploy/rollback.py |
The rollback commands for this environment, with its workflow IDs; and a check that the workflows are disabled and no finding from ISC arrived since | isc_deploy_checker, evidence_reader |
deploy/record.py |
Keeps an ISC response in the evidence folder with any secret field removed, prints its ID, enabled flag or status, and stops on an error | — |
deploy/step_evidence.py |
Every --out-json of the three checking scripts also appends a record to steps.jsonl beside it: the UTC time, the environment, the exact command, the result, the output file’s SHA-256, and the controls and KSIs the step supports, hash-chained the way evidence_export.py chains its records (Chapter 07). --verify <folder> --stage test checks the chain, every required step record (live, passing, its output file unchanged) and every required file |
— (reads files) |
deploy/deploy_common.py |
The shared code; run directly, it prints one value from a settings file or a kept response | — |
config/calls.json gains three tasks and four calls, each with its least privilege and the SailPoint specification as its source: deploy-check (list the workflows, sp:workflow:read; read the finding table as the evidence reader), smoke-raise (post to the Scripted REST resource as the finding writer), workflow-test (POST /v2025/workflows/{id}/test and GET /v2025/workflow-executions/{id}), and the workflow PATCH under the existing workflows task.101112 Every script refuses to run when the client ID in the environment isn’t the identity its step runs as. Nothing in deploy/ writes to ISC: the workflow changes are curl commands a person runs with the workflow administrator’s client, as the README already had it.
The tests
tests/python/test_deploy.py, 32 tests against fictional settings and saved responses in tests/fixtures/deploy/: the template’s placeholders and the refusal of a secret; that only the settings file differs between the stages; endpoint overrides; each pre-flight check, passing and failing; the rendered workflows and the secret’s path; the test inputs; the smoke test’s three phases and a wrong state; the wrong integration identity refused; the rollback plan and check; the kept responses; the step evidence records and their chain, a complete stage passing, and a gap, a tampered file, a fixture record or a failed execution failing; the least privilege of the new tasks; and that every call the scripts make is declared in config/calls.json for its task. The kit’s whole suite, 139 tests, passes.
The scripts below run on fictional fixtures. They show what each check looks for and what it prints, not that a ServiceNow instance answers in exactly these shapes. The Scripted REST resource’s answer, for one, may come inside result or at the top level, and the smoke test accepts both (kit README verify list, item 20).
What the scripts print on the fixtures
Run on November 2, 2026, from examples/servicenow-sailpoint, against tests/fixtures/deploy/. Nothing here signs in.
python -m pytest tests/python/test_deploy.py -q................................ [100%]
32 passed in 5.00s
The pre-flight check on the test stage after the three workflows were created. The WARN is SailPoint’s missing written confirmation of the HTTP Request step: the test stage may go on, production may not.
python deploy/preflight.py --settings tests/fixtures/deploy/environment.test.json --expect-workflows disabled --fixtures tests/fixtures/deploy/preflight.json --today 2026-11-02Preflight: test (settings tests/fixtures/deploy/environment.test.json), 2026-11-02, fixtures
PASS G1 settings no secrets in the file; no placeholders left
PASS G1 endpoints https://contosotest.service-now.com; https://example-sb.api.identitynow.com; no environment variable overrides them
PASS G1 marketplace F1305072116 and FR2001938710A recorded 2026-11-02 (0 days ago)
WARN G1 features not confirmed in writing: http_request_step (the test stage may go on; production may not)
PASS G1 auth ServiceNow: OAuth client credentials; ISC: client credentials; no basic-auth variables set
PASS G1 change change record CHG0040101
PASS G1 roles 7 integration identities hold exactly what their tasks need
PASS G4 instance GET /api/now/table/u_identity_finding answered as the evidence reader (0 of at most 1 row read)
PASS G4 workflows 3 of 3 found; disabled (expected disabled)
PASS G4 executions 0 executions, 0 failed
Result: 9 PASS, 1 WARN, 0 FAIL, 0 SKIP: go
The same command on production’s settings, a week in, with one failed execution to read:
python deploy/preflight.py --settings tests/fixtures/deploy/environment.production.json --expect-workflows enabled --fixtures tests/fixtures/deploy/preflight-week1.json --today 2026-11-09Preflight: production (settings tests/fixtures/deploy/environment.production.json), 2026-11-09, fixtures
PASS G1 settings no secrets in the file; no placeholders left
PASS G1 endpoints https://contoso.service-now.com; https://example.api.identitynow.com; no environment variable overrides them
PASS G1 marketplace F1305072116 and FR2001938710A recorded 2026-11-02 (7 days ago)
PASS G1 features SailPoint confirmed in writing: workflows, native_change_detection, http_request_step (SP-CASE-0000-EXAMPLE-2)
PASS G1 auth ServiceNow: OAuth client credentials; ISC: client credentials; no basic-auth variables set
PASS G1 change change record CHG0040188
PASS G1 roles 7 integration identities hold exactly what their tasks need
PASS G4 instance GET /api/now/table/u_identity_finding answered as the evidence reader (1 of at most 1 row read)
PASS G4 workflows 3 of 3 found; enabled (expected enabled)
WARN G4 executions 56 executions, 1 failed; read the failed executions of: Drift to ServiceNow - identity attributes changed (mover)
Result: 9 PASS, 1 WARN, 0 FAIL, 0 SKIP: go
The first workflow rendered for each environment. Only the settings file differs:
python deploy/render_workflows.py --settings tests/fixtures/deploy/environment.test.json --index 1 --summary
python deploy/render_workflows.py --settings tests/fixtures/deploy/environment.production.json --index 1 --summaryworkflow 1: Drift to ServiceNow - native change (provenance)
trigger idn:native-change-account-updated
url https://contosotest.service-now.com/api/x_example_idkit/identity_findings/finding
token url https://contosotest.service-now.com/oauth_token.do
client id a1b2c3d4e5f60718293a4b5c6d7e8f90
secret placeholder (pass --secret-env)
owner ttm.owner.example (2c9180000000000000000000000e9001)
enabled false
workflow 1: Drift to ServiceNow - native change (provenance)
trigger idn:native-change-account-updated
url https://contoso.service-now.com/api/x_example_idkit/identity_findings/finding
token url https://contoso.service-now.com/oauth_token.do
client id f0e1d2c3b4a5968778695a4b3c2d1e0f
secret placeholder (pass --secret-env)
owner ttm.owner.example (2c9180000000000000000000000e9101)
enabled false
The smoke test’s raise without --apply posts nothing; with --apply, against saved responses, it shows each expectation:
python deploy/smoke_test.py raise --settings tests/fixtures/deploy/environment.test.json --apply --fixtures tests/fixtures/deploy/smoke.json
python deploy/smoke_test.py signal --settings tests/fixtures/deploy/environment.test.json --apply --expect-moved 2 --fixtures tests/fixtures/deploy/smoke.json
python deploy/smoke_test.py check --settings tests/fixtures/deploy/environment.test.json --finding native --expect awaiting --occurrences 3 --fixtures tests/fixtures/deploy/smoke-check.json
python deploy/smoke_test.py check --settings tests/fixtures/deploy/environment.test.json --finding direct --expect closed --fixtures tests/fixtures/deploy/smoke-closed.jsonSmoke test raise: test, fixtures
PASS payload meets the data contract key drift-reconciliation|00000000-0000-4000-8000-00000000c501|attribute_drift|department
PASS first post creates (201, priority 4) HTTP 201, IDF0001001, priority 4
PASS repeat de-duplicates (200, same) HTTP 200, deduplicated True, occurrences 2
Result: PASS
Smoke test signal: test, fixtures
PASS signal moves findings to awaiting HTTP 200, moved 2 (expected 2)
Result: PASS
Smoke test check: test, fixtures
PASS finding native exists 1 record(s) with key sailpoint-isc|2c91800000000000000000000a5001ad|unauthorized_write
PASS state is awaiting IDF0001000 state 18
PASS occurrences 3 u_occurrences 3
Result: PASS
Smoke test check: test, fixtures
PASS finding direct exists 1 record(s) with key drift-reconciliation|00000000-0000-4000-8000-00000000c501|attribute_drift|department
PASS state is closed IDF0001001 state 3
PASS closed with re-read evidence evidence hash 9b1d5c0e7a3f..., verified 2026-11-02T16:10:00Z
Result: PASS
The rollback plan reads the workflows’ IDs; the check fails while a workflow is still on, and passes once all three are off and nothing new arrived:
python deploy/rollback.py --settings tests/fixtures/deploy/environment.test.json --plan --fixtures tests/fixtures/deploy/rollback-plan.json
python deploy/rollback.py --settings tests/fixtures/deploy/environment.test.json --verify --since "2026-11-02 16:30:00" --fixtures tests/fixtures/deploy/rollback-plan.json
python deploy/rollback.py --settings tests/fixtures/deploy/environment.test.json --verify --since "2026-11-02 16:30:00" --fixtures tests/fixtures/deploy/rollback.jsonRollback plan: test (tests/fixtures/deploy/environment.test.json)
# 1. Disable the three workflows (G4), as the ISC workflow administrator:
# Drift to ServiceNow - native change (provenance) (now enabled)
curl -s -X PATCH "https://example-sb.api.identitynow.com/v2025/workflows/wf-0000-0001" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json-patch+json" --data '[{"op": "replace", "path": "/enabled", "value": false}]'
# Drift to ServiceNow - identity attributes changed (mover) (now enabled)
curl -s -X PATCH "https://example-sb.api.identitynow.com/v2025/workflows/wf-0000-0002" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json-patch+json" --data '[{"op": "replace", "path": "/enabled", "value": false}]'
# Drift to ServiceNow - provisioning completed (closure signal) (now enabled)
curl -s -X PATCH "https://example-sb.api.identitynow.com/v2025/workflows/wf-0000-0003" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json-patch+json" --data '[{"op": "replace", "path": "/enabled", "value": false}]'
# 2. Stop the scheduled drift and re-read runs (G7) in your job runner.
# 3. Verify, as the deploy checker and the evidence reader:
python deploy/rollback.py --settings tests/fixtures/deploy/environment.test.json --verify --since "<rollback-start-utc>"
Rollback verify: test, fixtures
FAIL G4 workflows disabled 3 found, 3 enabled: Drift to ServiceNow - native change (provenance); Drift to ServiceNow - identity attributes changed (mover); Drift to ServiceNow - provisioning completed (closure signal)
FAIL G4 no new findings from ISC 1 created after 2026-11-02 16:30:00: IDF0001007
Result: not rolled back
Rollback verify: test, fixtures
PASS G4 workflows disabled 3 found, 0 enabled
PASS G4 no new findings from ISC 0 created after 2026-11-02 16:30:00
Result: rolled back
Each checking script, given --out-json, also writes the step’s evidence record. Run on November 2, 2026: a fixture pre-flight and a dry-run raise into an evidence folder, the first record, and the completeness check the go/no-go uses. The check fails, as it should: the records were made on fixtures and in a dry run, not live, and most of the stage’s evidence doesn’t exist yet. The listing below is cut after its first eight lines; the other twenty-three read no step record or missing in the same way.
python deploy/preflight.py --settings tests/fixtures/deploy/environment.test.json --expect-workflows disabled --fixtures tests/fixtures/deploy/preflight.json --today 2026-11-02 --out-json out/evidence/test/preflight-3-created.json
python deploy/smoke_test.py raise --settings tests/fixtures/deploy/environment.test.json --run-id test-smoke --out-json out/evidence/test/smoke-1-raise.json
python -c "import json; r=json.loads(open('out/evidence/test/steps.jsonl').readlines()[0]); print(json.dumps({k: r[k] for k in ('record','timestamp','environment','mode','command','result','summary','output_sha256','requirements','prev_sha256','record_sha256')}, indent=2))"
python deploy/step_evidence.py --verify out/evidence/test --stage test{
"record": "preflight-3-created",
"timestamp": "2026-11-02T12:18:18Z",
"environment": "test",
"mode": "fixtures",
"command": "python deploy/preflight.py --settings tests/fixtures/deploy/environment.test.json --expect-workflows disabled --fixtures tests/fixtures/deploy/preflight.json --today 2026-11-02 --out-json out/evidence/test/preflight-3-created.json",
"result": "pass",
"summary": "9 PASS, 1 WARN, 0 FAIL, 0 SKIP: go",
"output_sha256": "a59ba9075225575885fad51e90331e0832005cecce0ac882a74bae8930c90170",
"requirements": [
{"control": "SA-9", "ksi": ["KSI-SCR-MIT"]},
{"control": "AC-6", "ksi": ["KSI-IAM-ELP", "KSI-IAM-JIT"]},
{"control": "IA-5 (non-user)", "ksi": ["KSI-IAM-SNU"]},
{"control": "CM-3", "ksi": ["KSI-CMT-LMC", "KSI-CMT-RMV", "KSI-CMT-RVP", "KSI-CMT-VTD"]},
{"control": "CA-7", "ksi": ["KSI-MLA-EVC"]}
],
"prev_sha256": null,
"record_sha256": "9d8d13b938dc42b7342798ccb0f356093dea828305bf7fc5157db2ccaea6bf82"
}
PASS steps.jsonl chain 2 records, chain unbroken
FAIL preflight-2-installed no step record
FAIL preflight-3-created pass, fixtures, 2026-11-02T12:18:18Z; SA-9, AC-6, IA-5 (non-user), CM-3, CA-7; KSI-CMT-LMC, KSI-CMT-RMV, KSI-CMT-RVP, KSI-CMT-VTD, KSI-IAM-ELP, KSI-IAM-JIT, KSI-IAM-SNU, KSI-MLA-EVC, KSI-SCR-MIT
FAIL check-1-native no step record
FAIL check-2-mover no step record
FAIL check-3-native no step record
FAIL preflight-4-enabled no step record
FAIL smoke-1-raise pass, dry run (no --apply), 2026-11-02T12:18:24Z; CM-3(2), CM-4(2), AU-12; KSI-CMT-LMC, KSI-CMT-RVP, KSI-CMT-VTD, KSI-MLA-LET
Result: 1 of 32 present and passing: evidence incomplete
The record’s requirements entries are printed one per line here; the file holds the same values.
One environment settings file
Everything that differs between the test stage and production lives in one JSON file per environment: the ServiceNow and ISC addresses, the Graph app registration, each integration identity’s client ID and recorded grant, the workflow owner, the Gate 1 record, the change record and the synthetic worker. It never holds a secret: the kit’s loader refuses a secret key in a file, as Chapter 02 shows, and every secret comes from the vault into an environment variable for the length of one step. Keep both files in the agency’s repository, reviewed like code (design guidance). The upper-case keys are the kit’s own configuration keys, so the same file is the --config of the kit’s re-read client and evidence export.
Copy the template, once per environment:
cd examples/servicenow-sailpoint cp deploy/environment.example.json deploy/environment.test.json cp deploy/environment.example.json deploy/environment.production.jsonFill in each copy. Replace every
<...>.deploy.grantedrecords what each identity was actually granted, as the console shows it, comma-separated; the pre-flight check compares it with what the identity’s tasks need. Leavesailpoint_confirmedatfalseuntil SailPoint answers in writing (pre-flight, step 2). Then confirm nothing is left:python deploy/preflight.py --settings deploy/environment.test.json --dry-run python deploy/preflight.py --settings deploy/environment.production.json --dry-runExpect no
placeholders leftline. Theauthcheck fails until a step sets credentials; that’s expected here.Start every session the same way. Paste this block into a new shell before any step, with the settings file for the stage you’re working on. It sets the stage’s names from the file, defines
use_role(clears every credential and endpoint variable),as_snandas_isc(set one identity’s client ID from the file and prompt for its secret), andisc_token(an ISC token for the identity set):cd examples/servicenow-sailpoint export SETTINGS=deploy/environment.test.json export STAGE=$(python deploy/deploy_common.py "$SETTINGS" deploy.environment) export ISC=$(python deploy/deploy_common.py "$SETTINGS" SAILPOINT_API_BASE) export EVIDENCE=out/evidence/$STAGE mkdir -p "$EVIDENCE" use_role() { unset SN_CLIENT_ID SN_CLIENT_SECRET SN_ACCESS_TOKEN SN_USERNAME SN_PASSWORD SAILPOINT_CLIENT_ID SAILPOINT_CLIENT_SECRET SAILPOINT_ACCESS_TOKEN SN_INSTANCE SN_BASE_URL SAILPOINT_TENANT SAILPOINT_API_BASE; } as_sn() { export SN_CLIENT_ID=$(python deploy/deploy_common.py "$SETTINGS" deploy.clients.$1); read -rsp "ServiceNow client secret for $1, from the vault: " SN_CLIENT_SECRET; echo; export SN_CLIENT_SECRET; } as_isc() { export SAILPOINT_CLIENT_ID=$(python deploy/deploy_common.py "$SETTINGS" deploy.clients.$1); read -rsp "ISC client secret for $1, from the vault: " SAILPOINT_CLIENT_SECRET; echo; export SAILPOINT_CLIENT_SECRET; } isc_token() { export SAILPOINT_ACCESS_TOKEN=$(curl -s -X POST "$ISC/oauth/token" -d grant_type=client_credentials --data-urlencode client_id="$SAILPOINT_CLIENT_ID" --data-urlencode client_secret="$SAILPOINT_CLIENT_SECRET" | python -c "import json,sys; print(json.load(sys.stdin)['access_token'])"); } use_roleFor Stage 2 the only change is the second line:
export SETTINGS=deploy/environment.production.json.out/is ignored by git; copy the evidence folder to the agency’s evidence store at the end of each stage.
Pre-flight checks
Run these before Stage 1, and again before Stage 2 with the production settings. They fulfil G1 Boundary.
Re-read both FedRAMP listings on the day (G1, step 1). This prints the two listings from the Marketplace’s own data:
curl -s -o "$EVIDENCE/fedramp-products.json" https://www.fedramp.gov/marketplace/products.json python -c "import json,sys; d=json.load(open(sys.argv[1], encoding='utf-8')); print('last change', d['meta']['last_change']); P=d['data']['Products'] if isinstance(d['data'], dict) else d['data']; [print(p['fedramp_id'], p['cloud_service_offering'], p['status'], p['cert_class'], p['cert_path'], max(e['date'][:10] for e in p['event_log'] if e['description'].endswith('FedRAMP Certified'))) for p in P if p['fedramp_id'] in ('F1305072116', 'FR2001938710A')]" "$EVIDENCE/fedramp-products.json"Expect
F1305072116 Government Community Cloud FedRAMP Certified Class D JAB 2019-08-12andFR2001938710A SailPoint Identity Security Cloud FedRAMP Certified Class C Agency 2024-06-05, as they read on November 9, 2026. The Marketplace data now nests the listings underdata.Products, reports every listing’s impact level asUnknownand leaves its authorization date empty, so the command prints the certification class (Class D was the High baseline, Class C Moderate) and takes the date from the listing’s event log.13 Setdeploy.g1.marketplace_checked_onto today’s date in the settings file.Record SailPoint’s written answer on feature scope (G1, step 2). SailPoint says its FedRAMP-authorized ISC is hosted in AWS GovCloud and lists the modules it includes, but publishes no list of what isn’t available there, and its page doesn’t name Native Change Detection or the HTTP Request step.14 Ask SailPoint in writing whether Workflows, Native Change Detection and the workflow HTTP Request step are in the authorized environment your production tenant runs in. Set each of
deploy.g1.sailpoint_confirmed.workflows,native_change_detectionandhttp_request_steptotrueonly for a feature the answer confirms, anddeploy.g1.sailpoint_referenceto the answer’s case or letter number. The pre-flight check warns in the test stage and fails in production while any isfalse.Create the integration identities in this environment (G1, step 6), as Chapter 02 and Chapter 03 describe them:
- ServiceNow: one integration user per role, with only that role, and one inbound OAuth client-credentials integration per user, at the Machine Identity Console path Chapter 02 records. The token request is a form post to
/oauth_token.dowithgrant_type=client_credentials, the client ID and the secret.15 - ISC: three API clients at Admin > Global > Security Settings > API Management > Create API Client, each with only its scopes from the identities table; SailPoint’s guidance is to select only the scopes an application needs.16 The workflow tester is a personal access token of an
ORG_ADMINuser: as that user, the user icon > Preferences > Personal Access Tokens > New Token, with the two scopes and an expiry date.17 SailPoint’s token endpoint isPOST https://{tenant}.api.identitynow.com/oauth/token, and a tenant with a vanity domain finds its API address at/oauth/info.18 - Put each secret in the vault, each client ID in
deploy.clients, and what each was granted indeploy.granted.
- ServiceNow: one integration user per role, with only that role, and one inbound OAuth client-credentials integration per user, at the Machine Identity Console path Chapter 02 records. The token request is a form post to
Run the pre-flight check with the two identities it reads as. It refuses basic authentication outside a developer instance, which is the kit’s rule (design guidance), and every check it makes is in the list at the top of
deploy/preflight.py:use_role; as_sn evidence_reader; as_isc isc_deploy_checker python deploy/preflight.py --settings "$SETTINGS" --expect-workflows absent --out-json "$EVIDENCE/preflight-1-before.json" use_roleBefore the application is installed, expect one FAIL,
instance, because the finding table doesn’t exist yet, andworkflows 0 of 3 found; absent (expected absent); Step 1.1 runs the check again after the install, when it should endgo. Fix every other FAIL and run it again; don’t go on with one.
Requirements and evidence: pre-flight (G1).
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| SA-9 External System Services; FedRAMP use of authorized cloud services | Re-reads both Marketplace listings on the day; records SailPoint’s written feature scope; fails production without it | KSI-SCR-MIT | fedramp-products.json; the marketplace and features rows of preflight-*.json; their records in steps.jsonl |
| AC-6 Least Privilege | Compares each integration identity’s recorded grant with what its tasks need in config/calls.json |
KSI-IAM-ELP, KSI-IAM-JIT | The roles row of every preflight-*.json |
| AC-2 and IA-5 for non-user accounts | Seven integration identities, one per task; OAuth client credentials or a vault token; basic authentication refused; no secret in the settings file | KSI-IAM-SNU | The auth and settings rows of preflight-*.json |
| CM-3 Configuration Change Control | Checks the change record (required in production) | KSI-CMT-LMC, KSI-CMT-RVP | The change row of preflight-*.json; the change record |
| OMB M-22-09, section III.A: phishing-resistant MFA for agency staff and contractors19 | The people who make this runbook’s console changes sign in to ServiceNow, ISC and Entra with phishing-resistant MFA. The runbook assumes it and doesn’t check it (design guidance) | KSI-IAM-APM | The agency’s sign-in records for those sessions; not produced by the kit |
Stage 1: the live test
Where: the ServiceNow sub-production instance and the ISC sandbox tenant named in deploy/environment.test.json. Start the session block with that file.
Step 1.1: Install the ServiceNow application (G4, G6)
ServiceNow’s update set guidance says update sets aren’t meant for installing applications, which belong in the application repository or the Store.20 For a scoped application linked to source control, publishing from App Engine Studio commits the application, tags the version in source control and publishes it to the repository in one action.21 The same published version is then installed on the test instance and, after Stage 1, on production, so production gets exactly what was tested (design guidance).
Publish the version, on the development instance, as an administrator: All > App Engine > App Engine Studio; open the application from My Apps; select Publish; enter the version in
deploy.app.version, the release notes, and publish to your application repository; select Continue.22Install it, on the test instance, as an administrator: All > System Applications > My Company Applications; find the application, select the version next to it, and select Install.23
Set the system properties for this instance, as an administrator: in the navigation filter, enter
sys_properties.list, search for each property name, and set its value;24 the properties and what each holds are in the kit README.x_example_idkit.verifier_useris this instance’s verifier integration user.Run the pre-flight check again. The table now answers:
use_role; as_sn evidence_reader; as_isc isc_deploy_checker python deploy/preflight.py --settings "$SETTINGS" --expect-workflows absent --out-json "$EVIDENCE/preflight-2-installed.json" use_roleExpect
PASS G4 instanceandResult: ... 0 FAIL ...: go.
The business rule is active from the install, so a person’s close becomes Awaiting verification before any finding exists (G6) (design guidance).
Requirements and evidence: Step 1.1 (G4, G6).
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CM-3 Configuration Change Control; SA-10 Developer Configuration Management | Publishes one version, committed and tagged in source control, and installs that version; nothing is changed in place on the test instance | KSI-CMT-RMV, KSI-SCR-MIT | The source-control tag; deploy.app.version in the settings file; the instance’s application record |
| CM-5 Access Restrictions for Change | Only an administrator installs and sets properties; the integration identities can’t | KSI-CMT-RVP, KSI-IAM-JIT | The installer’s audit trail on the instance; the roles row of preflight-2-installed.json |
| CM-4(2) Verification of Controls | Re-runs the pre-flight check against the installed table | KSI-CMT-VTD | preflight-2-installed.json and its record in steps.jsonl |
Step 1.2: Turn on Native Change Detection (G3)
A console action, by the SailPoint administrator, on the Entra source named in deploy.synthetic.source_name: Admin > Connections > Sources; select the source; in Account Management, select Native Change Detection; turn on Enable Native Change Detection; choose the account operations and the attributes to watch, including department; select Save. SailPoint recommends watching all entitlement attributes for all account operations, notes that its workflow templates need that, and says to run an aggregation afterwards.25 Then start one: on the same source, in Account Management, select Account Aggregation, then Start Aggregation at the top of the page.26
Requirements and evidence: Step 1.2 (G3).
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CA-7 Continuous Monitoring | Turns on detection of changes made outside SailPoint on the Entra source | KSI-MLA-EVC | Step 1.4’s and Step 1.6’s native-change findings (check-1-native.json, smoke-3-native-changed.json), which show the detection working |
| CM-6 Configuration Settings | Records the source’s detection setting as a reviewed change | KSI-CMT-LMC | The change record’s note of the setting and its date (the kit doesn’t export it) |
Step 1.3: Create the three workflows, disabled (G4)
SailPoint creates workflows disabled: its specification says they can’t be created enabled.27 Each workflow posts to ServiceNow as the finding writer, so it needs that client’s secret, which goes from the vault to standard output and straight into curl, never to a file. record.py keeps each response without it.
use_role; as_isc isc_workflow_admin; isc_token
read -rsp "ServiceNow client secret for finding_writer, from the vault: " SN_WORKFLOW_CLIENT_SECRET; echo; export SN_WORKFLOW_CLIENT_SECRET
for n in 1 2 3; do python deploy/render_workflows.py --settings "$SETTINGS" --index $n --secret-env SN_WORKFLOW_CLIENT_SECRET | curl -s -X POST "$ISC/v2025/workflows" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" --data-binary @- | python deploy/record.py "$EVIDENCE/workflow-$n.json"; done
unset SN_WORKFLOW_CLIENT_SECRET; use_roleExpect three lines, id=... name=Drift to ServiceNow - ... enabled=False, one per workflow. A line that says stop and read it, or a detailCode, is SailPoint’s error: read the kept file, fix the cause, and delete any workflow that was created before running the loop again. Then check the state:
use_role; as_sn evidence_reader; as_isc isc_deploy_checker
python deploy/preflight.py --settings "$SETTINGS" --expect-workflows disabled --out-json "$EVIDENCE/preflight-3-created.json"
use_roleExpect PASS G4 workflows 3 of 3 found; disabled (expected disabled).
Step 1.4: Test-run each workflow while it’s disabled (G4)
SailPoint’s test endpoint runs a disabled workflow with an input you give it, returns an execution ID, and warns that the run is live.28 render_workflows.py --test-input builds each input from the kit’s event fixture with the synthetic worker’s IDs, so each finding a test raises has an intended state equal to the worker’s baseline, department = Smoke Test, and a later re-read can verify it. The tester’s ISC token and the evidence reader’s ServiceNow client are set together, because each test is followed by a read.
Set both identities:
use_role; as_isc isc_workflow_tester; isc_token; as_sn evidence_readerTest-run the native-change workflow, then read its execution:
WF=$(python deploy/deploy_common.py "$EVIDENCE/workflow-1.json" id) python deploy/render_workflows.py --settings "$SETTINGS" --test-input 1 | curl -s -X POST "$ISC/v2025/workflows/$WF/test" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" --data-binary @- | python deploy/record.py "$EVIDENCE/test-1.json" curl -s "$ISC/v2025/workflow-executions/$(python deploy/deploy_common.py "$EVIDENCE/test-1.json" workflowExecutionId)" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Accept: application/json" | python deploy/record.py "$EVIDENCE/execution-1.json"Expect
workflowExecutionId=..., thenstatus=Completed. The status is one ofCompleted,Failed,Canceled,RunningorQueued;29 while it’sRunningorQueued, run the last command again. Then read the finding it raised:python deploy/smoke_test.py check --settings "$SETTINGS" --finding native --expect open --occurrences 1 --out-json "$EVIDENCE/check-1-native.json"Expect
PASSonfinding native exists,state is openandoccurrences 1. AFailedexecution, or no finding, means the HTTP Request step didn’t reach ServiceNow: check the kit README’s verify list, items 2, 3 and 18, before anything else.Test-run the mover workflow, and read its finding:
WF=$(python deploy/deploy_common.py "$EVIDENCE/workflow-2.json" id) python deploy/render_workflows.py --settings "$SETTINGS" --test-input 2 | curl -s -X POST "$ISC/v2025/workflows/$WF/test" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" --data-binary @- | python deploy/record.py "$EVIDENCE/test-2.json" curl -s "$ISC/v2025/workflow-executions/$(python deploy/deploy_common.py "$EVIDENCE/test-2.json" workflowExecutionId)" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Accept: application/json" | python deploy/record.py "$EVIDENCE/execution-2.json" python deploy/smoke_test.py check --settings "$SETTINGS" --finding mover --expect open --occurrences 1 --out-json "$EVIDENCE/check-2-mover.json"Expect
status=Completed, thenPASSon all three.Test-run the closure-signal workflow, and read the native-change finding again:
WF=$(python deploy/deploy_common.py "$EVIDENCE/workflow-3.json" id) python deploy/render_workflows.py --settings "$SETTINGS" --test-input 3 | curl -s -X POST "$ISC/v2025/workflows/$WF/test" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" --data-binary @- | python deploy/record.py "$EVIDENCE/test-3.json" curl -s "$ISC/v2025/workflow-executions/$(python deploy/deploy_common.py "$EVIDENCE/test-3.json" workflowExecutionId)" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Accept: application/json" | python deploy/record.py "$EVIDENCE/execution-3.json" python deploy/smoke_test.py check --settings "$SETTINGS" --finding native --expect awaiting --occurrences 1 --out-json "$EVIDENCE/check-3-native.json" use_roleExpect
status=Completed, thenstate is awaiting: the signal named the Entra source, and the Scripted REST script moves matching findings to Awaiting verification, never to closed. The mover finding stays open, because it carries no source ID for the signal to match.
Step 1.5: Enable the workflows (G4)
Enabling is a JSON Patch on /enabled, with sp:workflow:manage.30
use_role; as_isc isc_workflow_admin; isc_token
for n in 1 2 3; do curl -s -X PATCH "$ISC/v2025/workflows/$(python deploy/deploy_common.py "$EVIDENCE/workflow-$n.json" id)" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json-patch+json" -H "Accept: application/json" --data '[{"op": "replace", "path": "/enabled", "value": true}]' | python deploy/record.py "$EVIDENCE/enable-$n.json"; done
use_role; as_sn evidence_reader; as_isc isc_deploy_checker
python deploy/preflight.py --settings "$SETTINGS" --expect-workflows enabled --out-json "$EVIDENCE/preflight-4-enabled.json"
use_roleExpect three enabled=True lines, then 3 of 3 found; enabled (expected enabled). The re-read client and the drift reconciliation stay unscheduled in Stage 1; they run by hand in the smoke test.
Requirements and evidence: Steps 1.3 to 1.5 (G4).
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CM-3(2) Testing, Validation, and Documentation of Changes | Creates the workflows disabled, test-runs each with the synthetic worker, reads each execution, then enables | KSI-CMT-VTD, KSI-CMT-LMC | workflow-1.json to workflow-3.json, test-*.json, execution-*.json (status=Completed), check-1-native.json to check-3-native.json, enable-*.json |
| CM-5 Access Restrictions for Change | Only the workflow administrator’s client changes a workflow; only an ORG_ADMIN token test-runs one; the deploy checker only reads |
KSI-CMT-RMV, KSI-IAM-JIT | The roles row of preflight-3-created.json and preflight-4-enabled.json; the workflows’ modifiedBy in the kept responses |
| CM-3 Configuration Change Control | Records the workflows’ state after each change | KSI-CMT-LMC | preflight-3-created.json (disabled), preflight-4-enabled.json (enabled) and their records |
| IA-5 for non-user accounts | The finding writer’s secret goes from the vault to the workflow without touching a file; kept responses have it removed | KSI-IAM-SNU | The [removed] field in workflow-*.json |
Step 1.6: Smoke test with the synthetic worker (G4, G6, G7)
The smoke test follows three synthetic findings from raised to closed: direct (posted by the script, as the drift client would), native (raised by the native-change workflow) and mover (raised by the mover workflow). Each step below says what to expect.
| Step | What you do | What to expect (an expectation; not yet seen live) |
|---|---|---|
| 1 | smoke_test.py raise --apply, as the finding writer |
201, priority 4; then 200, deduplicated True, the same record, occurrences 2 |
| 2 | smoke_test.py check --finding direct --expect open |
The record is open, occurrences 2 |
| 3 | Change the worker’s department in Entra, aggregate | Native Change Detection fires; the workflow posts; the active native finding de-duplicates: occurrences 2 |
| 4 | Set the department back, aggregate | The change back is also a native change: occurrences 3, still Awaiting verification |
| 5 | smoke_test.py signal --apply --expect-moved 2 |
200, the direct and mover findings moved to Awaiting verification |
| 6 | The re-read client, dry run, then --apply, as the verifier |
Three lines verified; would PATCH state=3; then each record closed with evidence |
| 7 | smoke_test.py check --expect closed, for each finding |
state is closed and closed with re-read evidence |
Raise the direct finding, and read it back:
use_role; as_sn finding_writer python deploy/smoke_test.py raise --settings "$SETTINGS" --apply --run-id "$STAGE-smoke" --out-json "$EVIDENCE/smoke-1-raise.json" use_role; as_sn evidence_reader python deploy/smoke_test.py check --settings "$SETTINGS" --finding direct --expect open --occurrences 2 --out-json "$EVIDENCE/smoke-2-direct-open.json" use_roleMake a native change. A console action by the Entra user administrator: Entra ID > Users; select the synthetic worker; Edit properties; Job information; set Department to
Smoke Test Changed; Save.31 Then the SailPoint administrator aggregates the Entra source: Admin > Connections > Sources; the source; Account Management > Account Aggregation > Start Aggregation.32 When the aggregation finishes:use_role; as_sn evidence_reader python deploy/smoke_test.py check --settings "$SETTINGS" --finding native --expect awaiting --occurrences 2 --out-json "$EVIDENCE/smoke-3-native-changed.json" use_roleIf Entra inbound provisioning writes
departmentin this environment, it may set the value back on its next cycle; that is the one-writer rule working (Chapter 08), and the next step does the same thing by hand.Set it back. The same console path, Department back to
Smoke Test, Save, and the same aggregation. Then:use_role; as_sn evidence_reader python deploy/smoke_test.py check --settings "$SETTINGS" --finding native --expect awaiting --occurrences 3 --out-json "$EVIDENCE/smoke-4-native-reverted.json" use_roleSend the closure signal for the synthetic worker:
use_role; as_sn finding_writer python deploy/smoke_test.py signal --settings "$SETTINGS" --apply --expect-moved 2 --run-id "$STAGE-smoke" --out-json "$EVIDENCE/smoke-5-signal.json" use_roleRe-read, as the verifier. The re-read client lists every record waiting for verification, re-reads each subject and closes only on a match (Chapter 05).
--grace-hours 0stops it waiting for an aggregation that has already run. On a new installation the smoke test’s three are the only waiting records; stop if the dry run lists any other (design guidance). The verifier reads ISC with the reader’s API client and Graph with the certificate the settings file names:use_role; as_sn verifier; as_isc isc_reader python clients/python/reread_verification.py --config "$SETTINGS" --grace-hours 0 --out-json "$EVIDENCE/smoke-6-reread-dry-run.json"Expect three lines,
[dry-run] IDF...: verified; would PATCH state=3. Amismatchline names what differs: fix the worker’s data, aggregate, and run it again. Then write the outcomes:python clients/python/reread_verification.py --config "$SETTINGS" --grace-hours 0 --apply --out-json "$EVIDENCE/smoke-7-reread-applied.json" use_roleExpect three lines,
IDF...: verified, record updated.Check each finding closed:
use_role; as_sn evidence_reader python deploy/smoke_test.py check --settings "$SETTINGS" --finding direct --expect closed --out-json "$EVIDENCE/smoke-8-direct-closed.json" python deploy/smoke_test.py check --settings "$SETTINGS" --finding native --expect closed --out-json "$EVIDENCE/smoke-8-native-closed.json" python deploy/smoke_test.py check --settings "$SETTINGS" --finding mover --expect closed --out-json "$EVIDENCE/smoke-8-mover-closed.json" use_roleExpect
Result: PASSthree times.
Requirements and evidence: Step 1.6 (G4, G6, G7).
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CM-4(2) Verification of Controls | Follows three synthetic findings from raised to closed; each closes only on a re-read that matches | KSI-CMT-VTD, KSI-CMT-LMC | smoke-1-raise.json to smoke-8-*-closed.json, smoke-6-reread-dry-run.json, smoke-7-reread-applied.json, and their records |
| CM-3(2) Testing, Validation, and Documentation of Changes | Proves de-duplication, the closure signal and the native-change path on the deployed version | KSI-CMT-VTD | smoke-1-raise.json (201, then 200), smoke-4-native-reverted.json (occurrences 3), smoke-5-signal.json (moved 2) |
| AC-5 Separation of Duties | The finding writer raises; only the verifier closes; the evidence reader reads | KSI-IAM-JIT | The identity each step ran as, in its record’s command and output; the checker identity in each closed record’s re-read evidence |
| CA-7 Continuous Monitoring; AU-12 Audit Record Generation | Each step leaves a timestamped, attributable record | KSI-MLA-EVC, KSI-MLA-LET | steps.jsonl |
| CISA BOD 25-01 (required configurations for Microsoft Entra ID)33 | Changes only the synthetic worker’s department; changes no tenant setting the required configurations cover (inference) |
KSI-MLA-EVC | The agency’s current SCuBA assessment results, unchanged; not produced by the kit |
Step 1.7: Capture the evidence (G7)
Export the closed synthetic findings as Book 13 evidence records (Chapter 07), verify the package, and list what the stage kept:
use_role; as_sn evidence_reader
python clients/python/evidence_export.py --config "$SETTINGS" --since "$(date -u +%F)" --period "$STAGE-smoke" --out-dir "$EVIDENCE/evidence-package"
python clients/python/evidence_export.py --verify-dir "$EVIDENCE/evidence-package"
use_role
ls -1 "$EVIDENCE"Expect 3 evidence records: 3 closed, ..., then Package holds: every file matches the manifest and the chain is unbroken. The listing is the stage’s evidence; the evidence table says what each file proves.
Requirements and evidence: Step 1.7 (G7).
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| AU-12 Audit Record Generation; CM-3 (records of changes retained) | Exports the closed synthetic findings as Book 13 evidence records | KSI-MLA-LET, KSI-CMT-LMC | evidence-package/ (records.jsonl, summary.json, manifest.json) |
| AU-9 Protection of Audit Information | Hash-chains the records and verifies the package; steps.jsonl is chained the same way |
KSI-MLA-OSM | The --verify-dir result; the steps.jsonl chain row of step_evidence.py --verify |
Step 1.8: Roll back, and prove it (G4, Rollback)
Rehearse the rollback in the test stage, so production’s is a second run. The guide’s rollback for the front door is to disable the workflows and keep the records, and for the re-read to stop the schedules; the records stay. This runbook doesn’t uninstall the application: ServiceNow says rolling back an application install removes its code, tables and files, that data lost that way needs a database restore, and that source-control installs aren’t recorded for rollback at all.34 The findings and their evidence would go with the tables (design guidance).
Note the time, and print the plan with this environment’s workflow IDs:
export ROLLBACK_START=$(date -u "+%Y-%m-%d %H:%M:%S") use_role; as_sn evidence_reader; as_isc isc_deploy_checker python deploy/rollback.py --settings "$SETTINGS" --plan | tee "$EVIDENCE/rollback-plan.txt" use_roleDisable the three workflows, as the workflow administrator:
use_role; as_isc isc_workflow_admin; isc_token for n in 1 2 3; do curl -s -X PATCH "$ISC/v2025/workflows/$(python deploy/deploy_common.py "$EVIDENCE/workflow-$n.json" id)" -H "Authorization: Bearer $SAILPOINT_ACCESS_TOKEN" -H "Content-Type: application/json-patch+json" -H "Accept: application/json" --data '[{"op": "replace", "path": "/enabled", "value": false}]' | python deploy/record.py "$EVIDENCE/disable-$n.json"; done use_roleExpect three
enabled=Falselines. The commands are the same as the plan’s.Verify:
use_role; as_sn evidence_reader; as_isc isc_deploy_checker python deploy/rollback.py --settings "$SETTINGS" --verify --since "$ROLLBACK_START" --out-json "$EVIDENCE/rollback-verify.json" use_roleExpect
Result: rolled back. The time comparison uses the instance’s time zone forsys_created_on(kit README verify list, item 24).Re-enable for the soak. Run Step 1.5 again, and leave the test stage running until the go/no-go meeting.
If the business rule itself is at fault, the guide’s Gate 6 rollback is to deactivate it: an administrator clears the rule’s Active flag, which ServiceNow defines as whether the rule is enforced.35 Closures then lose their evidence until it’s back, so record it in the change record.
Requirements and evidence: Step 1.8 (G4, Rollback).
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CP-10 System Recovery and Reconstitution, read for the integration (inference) | Rehearses the rollback and proves it took: workflows off, no new findings, records kept | KSI-RPL-ARP, KSI-RPL-TRC | rollback-plan.txt, disable-*.json, rollback-verify.json and its record |
| CM-3 Configuration Change Control | Each rollback action is a recorded change with its before and after state | KSI-CMT-LMC | rollback-plan.txt (now enabled), disable-*.json (enabled=False) |
| CM-5 Access Restrictions for Change | The rollback’s writes are the workflow administrator’s; the check is read-only | KSI-CMT-RMV, KSI-IAM-JIT | The commands in rollback-plan.txt; the rollback-verify record’s command |
Promotion go/no-go
The ISSO and the change manager decide on these, with Stage 1’s evidence folder in front of them. Every row must hold (design guidance).
| Criterion | The evidence that shows it |
|---|---|
| Every requirement row for the test stage has its evidence present and passing | python deploy/step_evidence.py --verify out/evidence/test --stage test ends evidence complete |
Every pre-flight run in Stage 1 from the install on ended go, with no FAIL (the run before the install is expected to show one FAIL, instance) |
preflight-2-installed.json to preflight-4-enabled.json |
| SailPoint confirmed in writing that Workflows, Native Change Detection and the HTTP Request step are in the production tenant’s authorized environment | deploy.g1 in environment.production.json; the answer itself, filed with the Gate 1 record |
Each workflow’s test run ended Completed and raised or moved the finding expected |
execution-1.json to execution-3.json; check-1-native.json to check-3-native.json |
| The smoke test passed every step, and the three findings closed only on a re-read | smoke-1-raise.json to smoke-8-*-closed.json; smoke-7-reread-applied.json |
| The evidence package verifies | evidence-package/ and the --verify-dir result |
| The rollback was rehearsed and verified | rollback-plan.txt, disable-1.json to disable-3.json, rollback-verify.json |
| No workflow execution failed during the soak | A pre-flight run on the day of the meeting: executions ... 0 failed |
| Nothing outside the kit’s declared calls was granted to make it work | roles PASS in every pre-flight; no change to config/calls.json without a reviewed pull request |
| The production change record is approved | The change record |
Run the completeness check on the test stage’s evidence folder, from examples/servicenow-sailpoint, and file its output with the decision:
python deploy/step_evidence.py --verify out/evidence/test --stage test | tee out/evidence/test/go-no-go-evidence.txtExpect one PASS line per requirement and Result: 32 of 32 present and passing: evidence complete. It checks the steps.jsonl chain; that each required step’s record is live, passed, and still matches its output file’s SHA-256; that every workflow, execution, enable and disable file is there and shows Completed, enabled=True or enabled=False; and that the evidence package verifies. A record made on fixtures or in a dry run doesn’t count.
A no-go leaves the test stage running, or rolled back, and names what must change. Any change to the application means a new published version and Stage 1 again from Step 1.1.
Stage 2: production
Where: the production ServiceNow instance in the Government Community Cloud and the production ISC tenant named in deploy/environment.production.json. Start a new shell with the session block, and export SETTINGS=deploy/environment.production.json on its second line. Every command below is the same as in Stage 1.
The change record (G1). Raised and approved as Before you start says, its number in
deploy.change_record. Work inside its window.Pre-flight (G1). Run the pre-flight checks, steps 1 to 4, with the production settings. In production a missing feature confirmation and a missing change record are FAILs, not warnings.
Install the tested version (G4, G6). Step 1.1, items 2 to 4 only: install the version Stage 1 tested, from All > System Applications > My Company Applications, on the production instance; don’t publish a new one. Set the production values of the system properties.
Native Change Detection (G3). Step 1.2, on the production Entra source.
Workflows, disabled; test-run; enable (G4). Steps 1.3, 1.4 and 1.5, with the production synthetic worker, after the ISSO’s approval for synthetic findings in production.
Smoke test and evidence (G4, G6, G7). Steps 1.6 and 1.7. Stop at the re-read dry run if it lists any record that isn’t one of the three.
Schedule the runs (G7). Last, and only after the smoke test passed. The agency’s job runner runs these two commands from
examples/servicenow-sailpoint, with the identities’ secrets from its own vault integration in the same environment variables: the drift reconciliation daily as the ISC reader and the Graph reader, and the re-read client on the cadence<grace-hours>was tuned for, as the verifier and the ISC reader:python clients/python/identity_drift.py --hr-csv "<hr-extract.csv>" --config deploy/environment.production.json --out-json "out/runs/drift-$(date -u +%Y%m%dT%H%M%SZ).json" --out-csv "out/runs/drift-$(date -u +%Y%m%dT%H%M%SZ).csv" python clients/python/reread_verification.py --config deploy/environment.production.json --apply --grace-hours "<grace-hours>" --out-json "out/runs/reread-$(date -u +%Y%m%dT%H%M%SZ).json"Neither posts drift findings to ServiceNow: the workflows do that.
--push-to-servicenowstays off unless the guide’s Gate 4 interim path is the agency’s choice.First-week monitoring (G7). Once a day for seven days, the deployer runs:
use_role; as_sn evidence_reader; as_isc isc_deploy_checker python deploy/preflight.py --settings "$SETTINGS" --expect-workflows enabled --out-json "$EVIDENCE/week1-$(date -u +%F)-preflight.json" use_role; as_sn verifier; as_isc isc_reader python clients/python/reread_verification.py --config "$SETTINGS" --out-json "$EVIDENCE/week1-$(date -u +%F)-waiting.json" use_roleThe first shows the workflows still enabled and their failure count; a
WARN G4 executionsnames the workflow whose failed executions to read in ISC, which keeps them for 90 days.36 The second is a dry run: it lists every record waiting for verification and what a re-read would do now. Expect the waiting list to empty between runs, and a burst of findings in the first days, which the guide calls the measurement working (Gate 3). At the end of the week, run Step 1.7 with--period "$STAGE-week1"and--sinceset to the go-live date, and give the folder to the ISSO.Rollback (G4, Rollback). Step 1.8, items 1 to 3, and stop the two scheduled runs in the job runner. The application stays installed and every record stays. A fault in the application itself is fixed forward with a corrected version through Stage 1 again, because a source-control install can’t be rolled back (design guidance).37
Requirements and evidence in production
The scripted steps write the same records to out/evidence/production/steps.jsonl, and the same check runs with --stage production at the end of item 6:
python deploy/step_evidence.py --verify out/evidence/production --stage production | tee out/evidence/production/go-live-evidence.txtExpect Result: 27 of 27 present and passing: evidence complete; production has no rollback rehearsal, so the rollback record and files aren’t required.
Items 1 to 3: change record, pre-flight, install.
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CM-3 Configuration Change Control; CM-3(4) Security and Privacy Representatives | An approved normal change, with the ISSO’s acceptance of Stage 1’s evidence, before anything is installed | KSI-CMT-RVP, KSI-CMT-LMC | The change record; out/evidence/test/go-no-go-evidence.txt |
| SA-9 External System Services; FedRAMP use of authorized cloud services | Pre-flight fails in production without SailPoint’s written feature confirmation and a Marketplace read within 30 days | KSI-SCR-MIT | fedramp-products.json; the marketplace and features rows of production’s preflight-*.json |
| AC-6; AC-2 and IA-5 for non-user accounts | Production’s seven identities checked as in the test stage | KSI-IAM-ELP, KSI-IAM-JIT, KSI-IAM-SNU | The roles and auth rows of production’s preflight-*.json |
| CM-3(2); SA-10 | Installs the version Stage 1 tested, not a rebuild | KSI-CMT-VTD, KSI-CMT-RMV, KSI-SCR-MIT | The version on the production instance equals deploy.app.version and the source-control tag; preflight-2-installed.json |
| OMB M-22-09, section III.A38 | Console changes by people with phishing-resistant MFA (design guidance) | KSI-IAM-APM | The agency’s sign-in records; not produced by the kit |
Items 4 to 6: detection, workflows, smoke test, evidence.
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CA-7; CM-6 | Native Change Detection on the production Entra source | KSI-MLA-EVC, KSI-CMT-LMC | Production’s check-1-native.json and smoke-3-native-changed.json; the change record’s note |
| CM-3(2); CM-5 | Workflows created disabled, test-run, then enabled, by the workflow administrator | KSI-CMT-VTD, KSI-CMT-LMC, KSI-CMT-RMV, KSI-IAM-JIT | Production’s workflow-*.json, execution-*.json, enable-*.json, preflight-3-created.json, preflight-4-enabled.json |
| CM-4(2); AC-5 | The synthetic findings close only on the verifier’s re-read | KSI-CMT-VTD, KSI-IAM-JIT | Production’s smoke-*.json; smoke-7-reread-applied.json |
| AU-12; AU-9 | Each step recorded and chained; the evidence package verifies | KSI-MLA-LET, KSI-MLA-OSM | steps.jsonl; evidence-package/; go-live-evidence.txt |
| CISA BOD 25-0139 | No tenant setting the required configurations cover is changed (inference) | KSI-MLA-EVC | The agency’s SCuBA results, unchanged |
Items 7 and 8: schedules and the first week.
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CA-7 Continuous Monitoring | The drift reconciliation and the re-read client run on a schedule; a daily pre-flight shows workflow failures | KSI-MLA-EVC | out/runs/drift-*.json, out/runs/reread-*.json; week1-*-preflight.json and their records |
| CM-4(2) Verification of Controls | Every closure in production comes from a re-read; the daily dry run lists what’s waiting | KSI-CMT-VTD, KSI-CMT-LMC | week1-*-waiting.json; the week’s evidence package |
| AU-12 Audit Record Generation | The week’s closed findings exported as evidence records | KSI-MLA-LET | The week-one evidence package and its --verify-dir result |
Item 9: rollback, if used.
| Requirement | What this step does | KSI it aligns to | Evidence the ISSO keeps |
|---|---|---|---|
| CP-10, read for the integration (inference); CM-3; CM-5 | The rehearsed rollback, on production: intake stopped, records kept | KSI-RPL-ARP, KSI-RPL-TRC, KSI-CMT-LMC, KSI-CMT-RMV | Production’s rollback-plan.txt, disable-*.json, rollback-verify.json and its record; the change record |
Evidence the ISSO keeps
Each stage leaves out/evidence/<stage>/. Copy it to the agency’s evidence store with the change record. The control mappings are the program’s, made the way Book 13’s Appendix A and the federal framework crosswalk make them; the authorizing official and assessors decide whether a control is satisfied.
| Files | What they prove | Requirement it supports | Stage |
|---|---|---|---|
fedramp-products.json, deploy.g1 and SailPoint’s written answer |
Each product’s authorization was read on the day, and the features relied on are inside it | SA-9 External System Services; FedRAMP use of authorized services (G1)40 | Both |
preflight-*.json |
Least privilege per identity, OAuth instead of basic authentication, no secret in a file, the change record, the workflow state at each step | AC-6, IA-5, CM-3 (G1, G4)41 | Both |
workflow-*.json, test-*.json, execution-*.json, enable-*.json |
What was deployed, that it was tested disabled before it was enabled, and by which identity | CM-3(2) testing, validation and documentation of changes; CM-5 access restrictions for change (G4)42 | Both |
check-*.json, smoke-*.json |
The front door, de-duplication, the closure signal and the re-read work end to end on a synthetic worker | CM-4(2) verification of controls; CA-7 (G4, G6)43 | Both |
steps.jsonl, and go-no-go-evidence.txt (test) or go-live-evidence.txt (production) |
One chained record per scripted step, with its command, result, controls and KSIs; the stage’s evidence complete | AU-9, AU-12, CM-3 (KSI-MLA-OSM, KSI-MLA-LET, KSI-CMT-LMC)44 | Both |
evidence-package/ |
The synthetic findings as Book 13 evidence records, hash-chained and verified | AU-12; CM-3 records of changes (G7)45 | Both |
rollback-plan.txt, disable-*.json, rollback-verify.json |
The rollback works and was proven | CM-3; CP-10 system recovery and reconstitution, read for the integration (inference)46 | Test; production if used |
| The change record and the published application version’s source-control tag | Production received the version that was tested, under approval | CM-3, CM-3(4) security representatives, SA-10 developer configuration management47 | Production |
week1-*.json and the week’s evidence package |
The first week ran within its windows and its failures were read | CA-7, AU-6 (G7)48 | Production |
The verified facts
| Item | Value | Source |
|---|---|---|
| ServiceNow Government Community Cloud | F1305072116; FedRAMP Certified, Class D (High), JAB path, certified August 12, 2019 | 49 |
| SailPoint Identity Security Cloud | FR2001938710A; FedRAMP Certified, Class C (Moderate), agency path, certified June 5, 2024 | 50 |
| SailPoint’s FedRAMP environment | Hosted in AWS GovCloud; modules listed; no list of unavailable features; Native Change Detection and the HTTP Request step not named | 51 |
| ServiceNow client-credentials token | POST /oauth_token.do; grant_type, client_id, client_secret required; scope optional (Zurich, updated October 8, 2026) |
52 |
| Publish from App Engine Studio | All > App Engine > App Engine Studio > Publish; commits to source control, tags the version, publishes to the repository or the Store; admin (Zurich) |
53 |
| Install from the application repository | All > System Applications > My Company Applications; select a version; Install; admin (Zurich) |
54 |
| Update sets | Not meant for installing applications; move from development to test to production; preview before commit (Zurich) | 55 |
| Application repository | Company instances entitled by default; not available to self-hosted customers; Federal Store customers sign in through a separate route (Zurich) | 56 |
| Rolling back an application | A repository install is recorded for rollback; it removes the code, table and file updates; data lost needs a database restore; source-control installs aren’t recorded for rollback | 57 |
| System properties | sys_properties.list in the navigation filter; admin (Zurich) |
58 |
Business rule active |
Whether the rule is enforced; rules live in sys_script (Zurich) |
59 |
| Change request | All > Change > Create New; Normal, Emergency or Standard; itil, admin or sn_change_write (Zurich) |
60 |
| ISC workflows | GET /v2025/workflows (sp:workflow:read or :manage); POST and PATCH (sp:workflow:manage); JSON Patch on /enabled; list and create name user level ORG_ADMIN |
61 |
| Created disabled | “Workflows cannot be created in an enabled state” | 62 |
| Test a workflow | POST /v2025/workflows/{id}/test; the workflow must be disabled; sp:workflow-execute:external; user level ORG_ADMIN; a live run; returns workflowExecutionId |
63 |
| Workflow execution | GET /v2025/workflow-executions/{id}; sp:workflow-execution:read or sp:workflow:manage; ORG_ADMIN; kept 90 days; Completed, Failed, Canceled, Running, Queued |
64 |
| ISC token and API address | POST https://{tenant}.api.identitynow.com/oauth/token; client credentials; personal access tokens; /oauth/info for a vanity domain |
65 |
| ISC API clients and tokens | Admin > Global > Security Settings > API Management; personal access tokens under the user’s Preferences; select only the scopes needed | 66 |
| Native Change Detection | Admin > Connections > Sources > source > Account Management > Native Change Detection; aggregate afterwards | 67 |
| Account aggregation | Source > Account Management > Account Aggregation > Start Aggregation | 68 |
| Entra user, create and edit | Entra ID > Users > New user > Create new user (Account enabled can be cleared); select a user > Edit properties > Job information; User Administrator | 6970 |
| GCC endpoints | Microsoft 365 GCC keeps the worldwide graph.microsoft.com |
71 |
| FedRAMP 20x KSIs | 46 indicators, each listing its related SP 800-53 controls; the pairs this chapter uses as the page gives them, for example KSI-CMT-VTD with CM-3(2) and CM-4(2), KSI-SCR-MIT with SA-9 and SA-10, KSI-RPL-TRC with CP-10, KSI-IAM-SNU with AC-2; the latest mapping change October 13, 2026 | 72 |
What couldn’t be verified
- That any of this works live. Nobody has run it against a live instance or tenant. Each “expect” is an expectation.
- Whether a workflow’s OAuth client secret can be set through the API. SailPoint’s workflow pages describe the HTTP Request step’s fields in the editor, not in JSON. If ISC doesn’t keep a secret sent in
oAuthClientSecret, enter it in the workflow editor instead (kit README verify list, items 2 and 21; research gaps, row 83). - Whether the test endpoint accepts the event shapes as the kit’s fixtures give them for the native-change and provisioning triggers, and whether the trigger input sits at
$or$.trigger(verify list, item 3). - The Zurich steps for rolling back an application install. The page found is a legacy page on a later release; the runbook doesn’t rely on it (verify list, item 23).
- How a Government Community Cloud instance reaches the application repository. The repository page notes a separate sign-in route for the Federal Store and doesn’t address the government cloud; ask ServiceNow before Stage 2 (research gaps, row 81).
- The production instance’s address in the Government Community Cloud; take it from the instance (verify list, item 22).
- The ISC account and identity attribute names the re-read compares with
department: the smoke test expects them to match Entra’s (inference; research gaps, row 82). - The instance time zone for
sys_created_onin the rollback check (research gaps, row 61). - The ISC API domain of a FedRAMP tenant (research gaps, row 22).
Federal requirements and evidence
| What the runbook proves | Requirement it supports | Who keeps it |
|---|---|---|
| Changes are tested in a test environment before production, and the same version goes to production | NIST SP 800-53 CM-3 and CM-3(2), in the Moderate baseline;73 the guide’s environments prerequisite | The deployer, in the evidence folder; the change manager |
| The change is verified after it’s made, on a synthetic subject | CM-4 and CM-4(2), Moderate74 | The ISSO, from the smoke test’s files |
| Only the declared identities, with their least privilege, make the changes | AC-6, CM-5 and IA-5, Moderate75 | The pre-flight results; the identity register (G1) |
| External services are authorized and their scope is confirmed | SA-9, Moderate;76 FedRAMP | The Gate 1 record |
| The deployment can be undone without losing records | CP-10 read for the integration (inference); CM-377 | The rollback rehearsal’s files |
Book 13 maps the loop’s controls in Appendix A; this chapter adds only the deployment’s.
Dangers
| Danger | What happens | The guard |
|---|---|---|
| A command meant for test runs against production | Synthetic findings, or a disabled workflow, in the wrong place | One settings file per stage; STAGE and the evidence folder named from it; pre-flight fails when an endpoint variable overrides the file |
| A secret in the settings file or the evidence folder | It reaches the repository or the evidence store | The kit’s loader refuses a secret key; secrets are prompted for, not typed; record.py removes secret fields |
| The wrong identity for a step | A check runs as the writer, or a write as the reader | Every script refuses a client ID that isn’t its step’s role; use_role clears credentials between steps |
| A workflow enabled before it was tested | Bad posts on the first real event | Created disabled by SailPoint; Step 1.4 tests while disabled; pre-flight checks the state at each step |
| A feature outside the authorization used in production | A finding the authorizing official didn’t accept | Pre-flight fails in production without SailPoint’s written confirmation |
| A rebuilt version in production | Production differs from what was tested | Stage 2 installs the published version Stage 1 tested; it doesn’t publish |
| The rollback uninstalls the application | Every finding and its evidence goes with the tables | The rollback disables intake and keeps the records; a fix goes forward |
| The re-read applied to records nobody expected | Real findings closed during a smoke test | The dry run first; stop if it lists anything but the three synthetic findings |
| Basic authentication left on | A password in a pipeline | Pre-flight fails while SN_USERNAME or SN_PASSWORD is set |
| Failures nobody reads in week one | A broken workflow raises nothing, quietly | Daily pre-flight with execution counts; a WARN names the workflow |
Checklist
Footnotes
FedRAMP, “Key Security Indicators,” FedRAMP Consolidated Rules for 2026 (46 indicators, each with its statement and “Related SP 800-53 Controls”; the changelogs’ latest control mapping update October 13, 2026), https://www.fedramp.gov/2026/reference/key-security-indicators/ (read November 2, 2026).↩︎
ServiceNow, “Install an application from the application repository” (Zurich, last updated July 31, 2025: role
admin; All > System Applications > My Company Applications, find the application, select a version, Install), https://www.servicenow.com/docs/bundle/zurich-application-development/page/build/applications/task/install-app-from-repo.html (read November 2, 2026).↩︎ServiceNow, “Add a system property” (Zurich, last updated July 31, 2025: role
admin; entersys_properties.listin the navigation filter, search for the property, set its value), https://www.servicenow.com/docs/r/7LhbZn3yz3Q58qhjZoU9iQ/n_jwpkPYhvDkhsR0uXx7XA (read November 2, 2026).↩︎SailPoint, “Managing API Keys and Personal Access Tokens” (Admin > Global > Security Settings > API Management > Create API Client; personal access tokens under the user icon > Preferences > Personal Access Tokens; select only the scopes the application needs), https://documentation.sailpoint.com/saas/help/common/api_keys.html (read November 2, 2026).↩︎
SailPoint, Identity Security Cloud OpenAPI specification, v2025,
testWorkflow(the workflow must be disabled;sp:workflow-execute:external; user levelORG_ADMIN; a live run; returnsworkflowExecutionId), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow-test.yaml (read November 2, 2026, at commit5a6ea75).↩︎Microsoft Learn, “How to create, invite, and delete users” (at least User Administrator; Entra ID > Users > New user > Create new user; Account enabled checked by default and can be cleared; job information on the Properties tab), https://learn.microsoft.com/entra/fundamentals/how-to-create-delete-users (read November 2, 2026).↩︎
Microsoft Learn, “Add or update a user’s profile information and settings in the Microsoft Entra admin center” (at least User Administrator; Entra ID > Users, select a user, Edit properties, the Job information category including department, Save), https://learn.microsoft.com/entra/fundamentals/how-to-manage-user-profile-info (read November 2, 2026).↩︎
ServiceNow, “Create a change request” (Zurich, last updated January 30, 2025: roles
itil,adminorsn_change_write; All > Change > Create New; Normal, Emergency or Standard), https://www.servicenow.com/docs/r/MlbQAgTiiiMOLOw9T36wJg/cloAfdFE6aOH0vR3nT28vw (read November 2, 2026).↩︎Microsoft Learn, “How to create, invite, and delete users” (at least User Administrator; Entra ID > Users > New user > Create new user; Account enabled checked by default and can be cleared; job information on the Properties tab), https://learn.microsoft.com/entra/fundamentals/how-to-create-delete-users (read November 2, 2026).↩︎
SailPoint, Identity Security Cloud OpenAPI specification, v2025:
listWorkflows(sp:workflow:readorsp:workflow:manage; user levelORG_ADMIN),createWorkflow(sp:workflow:manage; user levelORG_ADMIN),patchWorkflow(sp:workflow:manage; JSON Patch, including/enabled), and the serverhttps://{tenant}.api.identitynow.com/v2025, https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflows.yaml, https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow.yaml and https://github.com/sailpoint-oss/api-specs/blob/main/idn/sailpoint-api.v2025.yaml (read November 2, 2026, at commit5a6ea75;listWorkflowsandcreateWorkflowre-read November 9, 2026, at commit2a1f293, which adds user levelORG_ADMINto both).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025,
testWorkflow(the workflow must be disabled;sp:workflow-execute:external; user levelORG_ADMIN; a live run; returnsworkflowExecutionId), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow-test.yaml (read November 2, 2026, at commit5a6ea75).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025,
getWorkflowExecution(sp:workflow-execution:readorsp:workflow:manage; user levelORG_ADMIN; executions kept for up to 90 days) andWorkflowExecution(statusCompleted,Failed,Canceled,Running,Queued), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow-execution.yaml and https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/schemas/workflows/WorkflowExecution.yaml (read November 2, 2026, at commit5a6ea75).↩︎FedRAMP Marketplace data, https://www.fedramp.gov/marketplace/products.json (
last_change2026-11-09T05:06:48Z): ServiceNow Government Community Cloud (F1305072116: FedRAMP Certified, Class D, JAB path, certified August 12, 2019, from its event log); SailPoint Identity Security Cloud (FR2001938710A: FedRAMP Certified, Class C, agency path, certified June 5, 2024, from its event log); listings underdata.Products,impact_levelUnknownandfedramp_authempty for every listing (read November 9, 2026; first read November 2, 2026, when the data still gave High and Moderate).↩︎SailPoint, “Identity for government and critical infrastructure” (FedRAMP Moderate ATO; hosted in AWS GovCloud; core modules and advanced capabilities listed; no list of unavailable features; Native Change Detection and the HTTP Request step not mentioned), https://www.sailpoint.com/solutions/fedramp-isc (read November 2, 2026).↩︎
ServiceNow, “Client credentials grant workflow” (Zurich, last updated October 8, 2026:
POST /oauth_token.do,grant_type,client_idandclient_secretrequired,scopeoptional), https://www.servicenow.com/docs/r/oJu9n0q6rU~F9UHAnNCt5w/nEdqo82hKBPEeGDqhx~hqw (read November 2, 2026).↩︎SailPoint, “Managing API Keys and Personal Access Tokens” (Admin > Global > Security Settings > API Management > Create API Client; personal access tokens under the user icon > Preferences > Personal Access Tokens; select only the scopes the application needs), https://documentation.sailpoint.com/saas/help/common/api_keys.html (read November 2, 2026).↩︎
SailPoint, “Managing API Keys and Personal Access Tokens” (Admin > Global > Security Settings > API Management > Create API Client; personal access tokens under the user icon > Preferences > Personal Access Tokens; select only the scopes the application needs), https://documentation.sailpoint.com/saas/help/common/api_keys.html (read November 2, 2026).↩︎
SailPoint Developer, “Authentication” (
POST https://[tenant].api.identitynow.com/oauth/token; the client credentials grant; personal access tokens;/oauth/infofor a tenant with a vanity domain), https://developer.sailpoint.com/docs/api/authentication (read November 2, 2026).↩︎Office of Management and Budget, M-22-09, Moving the U.S. Government Toward Zero Trust Cybersecurity Principles, January 26, 2022, section III.A (Identity: phishing-resistant MFA is required for agency staff, contractors and partners), https://www.whitehouse.gov/wp-content/uploads/2022/01/M-22-09.pdf (accessed October 21, 2026, as cited in Book 01, Chapter 04).↩︎
ServiceNow, “Get started with update sets” (Zurich, last updated July 31, 2025: update sets aren’t meant for installing applications, which use the application repository or the Store; move from development to test to production; preview before committing), https://www.servicenow.com/docs/r/guL1zqmJkV9eywMq_6qu~w/Dzl1AsfhhtvmdXMY_EBTVA (read November 2, 2026).↩︎
ServiceNow, “Publish an app from App Engine Studio when linked to source control” (Zurich, last updated July 31, 2025: role
admin; All > App Engine > App Engine Studio, the app, Publish, version, release notes, repository or Store, Continue; commits the application’s current state, creates a source control tag and publishes), https://www.servicenow.com/docs/r/guL1zqmJkV9eywMq_6qu~w/x5QEx_AV7eOC21RMqOqcVw (read November 2, 2026).↩︎ServiceNow, “Publish an app from App Engine Studio when linked to source control” (Zurich, last updated July 31, 2025: role
admin; All > App Engine > App Engine Studio, the app, Publish, version, release notes, repository or Store, Continue; commits the application’s current state, creates a source control tag and publishes), https://www.servicenow.com/docs/r/guL1zqmJkV9eywMq_6qu~w/x5QEx_AV7eOC21RMqOqcVw (read November 2, 2026).↩︎ServiceNow, “Install an application from the application repository” (Zurich, last updated July 31, 2025: role
admin; All > System Applications > My Company Applications, find the application, select a version, Install), https://www.servicenow.com/docs/bundle/zurich-application-development/page/build/applications/task/install-app-from-repo.html (read November 2, 2026).↩︎ServiceNow, “Add a system property” (Zurich, last updated July 31, 2025: role
admin; entersys_properties.listin the navigation filter, search for the property, set its value), https://www.servicenow.com/docs/r/7LhbZn3yz3Q58qhjZoU9iQ/n_jwpkPYhvDkhsR0uXx7XA (read November 2, 2026).↩︎SailPoint, “Managing Native Change Detection” (Admin > Connections > Sources; Account Management > Native Change Detection; Enable Native Change Detection; operations and attributes; all entitlement attributes for all operations recommended and needed by the workflow templates; aggregate after saving), https://documentation.sailpoint.com/saas/help/sources/native_change_detection.html (read November 2, 2026).↩︎
SailPoint, “Loading Account Data” (Admin > Connections > Sources; Account Management > Account Aggregation; Start Aggregation), https://documentation.sailpoint.com/saas/help/accounts/loading_data.html (read November 2, 2026).↩︎
SailPoint, Identity Security Cloud OpenAPI specification, v2025,
WorkflowBody(“Workflows cannot be created in an enabled state”), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/schemas/workflows/WorkflowBody.yaml (read November 2, 2026, at commit5a6ea75).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025,
testWorkflow(the workflow must be disabled;sp:workflow-execute:external; user levelORG_ADMIN; a live run; returnsworkflowExecutionId), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow-test.yaml (read November 2, 2026, at commit5a6ea75).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025,
getWorkflowExecution(sp:workflow-execution:readorsp:workflow:manage; user levelORG_ADMIN; executions kept for up to 90 days) andWorkflowExecution(statusCompleted,Failed,Canceled,Running,Queued), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow-execution.yaml and https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/schemas/workflows/WorkflowExecution.yaml (read November 2, 2026, at commit5a6ea75).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025:
listWorkflows(sp:workflow:readorsp:workflow:manage; user levelORG_ADMIN),createWorkflow(sp:workflow:manage; user levelORG_ADMIN),patchWorkflow(sp:workflow:manage; JSON Patch, including/enabled), and the serverhttps://{tenant}.api.identitynow.com/v2025, https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflows.yaml, https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow.yaml and https://github.com/sailpoint-oss/api-specs/blob/main/idn/sailpoint-api.v2025.yaml (read November 2, 2026, at commit5a6ea75;listWorkflowsandcreateWorkflowre-read November 9, 2026, at commit2a1f293, which adds user levelORG_ADMINto both).↩︎Microsoft Learn, “Add or update a user’s profile information and settings in the Microsoft Entra admin center” (at least User Administrator; Entra ID > Users, select a user, Edit properties, the Job information category including department, Save), https://learn.microsoft.com/entra/fundamentals/how-to-manage-user-profile-info (read November 2, 2026).↩︎
SailPoint, “Loading Account Data” (Admin > Connections > Sources; Account Management > Account Aggregation; Start Aggregation), https://documentation.sailpoint.com/saas/help/accounts/loading_data.html (read November 2, 2026).↩︎
Cybersecurity and Infrastructure Security Agency, “BOD 25-01: Implementing Secure Practices for Cloud Services Required Configurations,” Microsoft Entra ID policies, https://www.cisa.gov/resources-tools/services/bod-25-01-implementing-secure-practices-cloud-services-required-configurations (accessed October 21, 2026, as cited in Book 01, Chapter 04).↩︎
ServiceNow, “Legacy - Roll back, back out, and uninstall” (Australia, last updated March 12, 2026: an application repository installation is recorded for rollback; a rollback removes all code, table and file updates from the installation; data lost from a bad installation needs a database restore; source control installations aren’t recorded for rollback; deleting a scoped application’s record destroys its schema and data), https://www.servicenow.com/docs/r/9Lur8HBNLjdzEcjznSAFzA/h1IBZegfwtLdM9hzQ7ANIw (read November 2, 2026).↩︎
ServiceNow, “Business Rule API - ServiceNow Fluent” (Zurich, last updated March 12, 2026:
active, “Flag that indicates whether the business rule is enabled”; business rules insys_script), https://www.servicenow.com/docs/r/guL1zqmJkV9eywMq_6qu~w/hFJKYb~~sBTX2m4i~EzS4Q (read November 2, 2026).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025,
getWorkflowExecution(sp:workflow-execution:readorsp:workflow:manage; user levelORG_ADMIN; executions kept for up to 90 days) andWorkflowExecution(statusCompleted,Failed,Canceled,Running,Queued), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow-execution.yaml and https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/schemas/workflows/WorkflowExecution.yaml (read November 2, 2026, at commit5a6ea75).↩︎ServiceNow, “Legacy - Roll back, back out, and uninstall” (Australia, last updated March 12, 2026: an application repository installation is recorded for rollback; a rollback removes all code, table and file updates from the installation; data lost from a bad installation needs a database restore; source control installations aren’t recorded for rollback; deleting a scoped application’s record destroys its schema and data), https://www.servicenow.com/docs/r/9Lur8HBNLjdzEcjznSAFzA/h1IBZegfwtLdM9hzQ7ANIw (read November 2, 2026).↩︎
Office of Management and Budget, M-22-09, Moving the U.S. Government Toward Zero Trust Cybersecurity Principles, January 26, 2022, section III.A (Identity: phishing-resistant MFA is required for agency staff, contractors and partners), https://www.whitehouse.gov/wp-content/uploads/2022/01/M-22-09.pdf (accessed October 21, 2026, as cited in Book 01, Chapter 04).↩︎
Cybersecurity and Infrastructure Security Agency, “BOD 25-01: Implementing Secure Practices for Cloud Services Required Configurations,” Microsoft Entra ID policies, https://www.cisa.gov/resources-tools/services/bod-25-01-implementing-secure-practices-cloud-services-required-configurations (accessed October 21, 2026, as cited in Book 01, Chapter 04).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
FedRAMP Marketplace data, https://www.fedramp.gov/marketplace/products.json (
last_change2026-11-09T05:06:48Z): ServiceNow Government Community Cloud (F1305072116: FedRAMP Certified, Class D, JAB path, certified August 12, 2019, from its event log); SailPoint Identity Security Cloud (FR2001938710A: FedRAMP Certified, Class C, agency path, certified June 5, 2024, from its event log); listings underdata.Products,impact_levelUnknownandfedramp_authempty for every listing (read November 9, 2026; first read November 2, 2026, when the data still gave High and Moderate).↩︎FedRAMP Marketplace data, https://www.fedramp.gov/marketplace/products.json (
last_change2026-11-09T05:06:48Z): ServiceNow Government Community Cloud (F1305072116: FedRAMP Certified, Class D, JAB path, certified August 12, 2019, from its event log); SailPoint Identity Security Cloud (FR2001938710A: FedRAMP Certified, Class C, agency path, certified June 5, 2024, from its event log); listings underdata.Products,impact_levelUnknownandfedramp_authempty for every listing (read November 9, 2026; first read November 2, 2026, when the data still gave High and Moderate).↩︎SailPoint, “Identity for government and critical infrastructure” (FedRAMP Moderate ATO; hosted in AWS GovCloud; core modules and advanced capabilities listed; no list of unavailable features; Native Change Detection and the HTTP Request step not mentioned), https://www.sailpoint.com/solutions/fedramp-isc (read November 2, 2026).↩︎
ServiceNow, “Client credentials grant workflow” (Zurich, last updated October 8, 2026:
POST /oauth_token.do,grant_type,client_idandclient_secretrequired,scopeoptional), https://www.servicenow.com/docs/r/oJu9n0q6rU~F9UHAnNCt5w/nEdqo82hKBPEeGDqhx~hqw (read November 2, 2026).↩︎ServiceNow, “Publish an app from App Engine Studio when linked to source control” (Zurich, last updated July 31, 2025: role
admin; All > App Engine > App Engine Studio, the app, Publish, version, release notes, repository or Store, Continue; commits the application’s current state, creates a source control tag and publishes), https://www.servicenow.com/docs/r/guL1zqmJkV9eywMq_6qu~w/x5QEx_AV7eOC21RMqOqcVw (read November 2, 2026).↩︎ServiceNow, “Install an application from the application repository” (Zurich, last updated July 31, 2025: role
admin; All > System Applications > My Company Applications, find the application, select a version, Install), https://www.servicenow.com/docs/bundle/zurich-application-development/page/build/applications/task/install-app-from-repo.html (read November 2, 2026).↩︎ServiceNow, “Get started with update sets” (Zurich, last updated July 31, 2025: update sets aren’t meant for installing applications, which use the application repository or the Store; move from development to test to production; preview before committing), https://www.servicenow.com/docs/r/guL1zqmJkV9eywMq_6qu~w/Dzl1AsfhhtvmdXMY_EBTVA (read November 2, 2026).↩︎
ServiceNow, “ServiceNow application repository” (Zurich, last updated July 31, 2025: company instances entitled automatically by default; not available to self-hosted customers; a separate sign-in route for Federal Store customers), https://www.servicenow.com/docs/r/guL1zqmJkV9eywMq_6qu~w/GPzhZ2fTLeFKG11v0urMJg (read November 2, 2026).↩︎
ServiceNow, “Legacy - Roll back, back out, and uninstall” (Australia, last updated March 12, 2026: an application repository installation is recorded for rollback; a rollback removes all code, table and file updates from the installation; data lost from a bad installation needs a database restore; source control installations aren’t recorded for rollback; deleting a scoped application’s record destroys its schema and data), https://www.servicenow.com/docs/r/9Lur8HBNLjdzEcjznSAFzA/h1IBZegfwtLdM9hzQ7ANIw (read November 2, 2026).↩︎
ServiceNow, “Add a system property” (Zurich, last updated July 31, 2025: role
admin; entersys_properties.listin the navigation filter, search for the property, set its value), https://www.servicenow.com/docs/r/7LhbZn3yz3Q58qhjZoU9iQ/n_jwpkPYhvDkhsR0uXx7XA (read November 2, 2026).↩︎ServiceNow, “Business Rule API - ServiceNow Fluent” (Zurich, last updated March 12, 2026:
active, “Flag that indicates whether the business rule is enabled”; business rules insys_script), https://www.servicenow.com/docs/r/guL1zqmJkV9eywMq_6qu~w/hFJKYb~~sBTX2m4i~EzS4Q (read November 2, 2026).↩︎ServiceNow, “Create a change request” (Zurich, last updated January 30, 2025: roles
itil,adminorsn_change_write; All > Change > Create New; Normal, Emergency or Standard), https://www.servicenow.com/docs/r/MlbQAgTiiiMOLOw9T36wJg/cloAfdFE6aOH0vR3nT28vw (read November 2, 2026).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025:
listWorkflows(sp:workflow:readorsp:workflow:manage; user levelORG_ADMIN),createWorkflow(sp:workflow:manage; user levelORG_ADMIN),patchWorkflow(sp:workflow:manage; JSON Patch, including/enabled), and the serverhttps://{tenant}.api.identitynow.com/v2025, https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflows.yaml, https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow.yaml and https://github.com/sailpoint-oss/api-specs/blob/main/idn/sailpoint-api.v2025.yaml (read November 2, 2026, at commit5a6ea75;listWorkflowsandcreateWorkflowre-read November 9, 2026, at commit2a1f293, which adds user levelORG_ADMINto both).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025,
WorkflowBody(“Workflows cannot be created in an enabled state”), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/schemas/workflows/WorkflowBody.yaml (read November 2, 2026, at commit5a6ea75).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025,
testWorkflow(the workflow must be disabled;sp:workflow-execute:external; user levelORG_ADMIN; a live run; returnsworkflowExecutionId), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow-test.yaml (read November 2, 2026, at commit5a6ea75).↩︎SailPoint, Identity Security Cloud OpenAPI specification, v2025,
getWorkflowExecution(sp:workflow-execution:readorsp:workflow:manage; user levelORG_ADMIN; executions kept for up to 90 days) andWorkflowExecution(statusCompleted,Failed,Canceled,Running,Queued), https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/paths/workflows/workflow-execution.yaml and https://github.com/sailpoint-oss/api-specs/blob/main/idn/v2025/schemas/workflows/WorkflowExecution.yaml (read November 2, 2026, at commit5a6ea75).↩︎SailPoint Developer, “Authentication” (
POST https://[tenant].api.identitynow.com/oauth/token; the client credentials grant; personal access tokens;/oauth/infofor a tenant with a vanity domain), https://developer.sailpoint.com/docs/api/authentication (read November 2, 2026).↩︎SailPoint, “Managing API Keys and Personal Access Tokens” (Admin > Global > Security Settings > API Management > Create API Client; personal access tokens under the user icon > Preferences > Personal Access Tokens; select only the scopes the application needs), https://documentation.sailpoint.com/saas/help/common/api_keys.html (read November 2, 2026).↩︎
SailPoint, “Managing Native Change Detection” (Admin > Connections > Sources; Account Management > Native Change Detection; Enable Native Change Detection; operations and attributes; all entitlement attributes for all operations recommended and needed by the workflow templates; aggregate after saving), https://documentation.sailpoint.com/saas/help/sources/native_change_detection.html (read November 2, 2026).↩︎
SailPoint, “Loading Account Data” (Admin > Connections > Sources; Account Management > Account Aggregation; Start Aggregation), https://documentation.sailpoint.com/saas/help/accounts/loading_data.html (read November 2, 2026).↩︎
Microsoft Learn, “How to create, invite, and delete users” (at least User Administrator; Entra ID > Users > New user > Create new user; Account enabled checked by default and can be cleared; job information on the Properties tab), https://learn.microsoft.com/entra/fundamentals/how-to-create-delete-users (read November 2, 2026).↩︎
Microsoft Learn, “Add or update a user’s profile information and settings in the Microsoft Entra admin center” (at least User Administrator; Entra ID > Users, select a user, Edit properties, the Job information category including department, Save), https://learn.microsoft.com/entra/fundamentals/how-to-manage-user-profile-info (read November 2, 2026).↩︎
Microsoft Learn, “Microsoft Graph national cloud deployments” (Microsoft 365 GCC continues to use the worldwide endpoints,
https://graph.microsoft.com), https://learn.microsoft.com/graph/deployments (read November 2, 2026).↩︎FedRAMP, “Key Security Indicators,” FedRAMP Consolidated Rules for 2026 (46 indicators, each with its statement and “Related SP 800-53 Controls”; the changelogs’ latest control mapping update October 13, 2026), https://www.fedramp.gov/2026/reference/key-security-indicators/ (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎
National Institute of Standards and Technology, SP 800-53B Moderate baseline, release 5.2.0 OSCAL profile (includes AC-2, AC-5, AC-6, AU-6, AU-9, AU-12, CA-7, CM-3, CM-3(2), CM-3(4), CM-4, CM-4(2), CM-5, CM-6, CP-10, IA-5, SA-9 and SA-10), https://github.com/usnistgov/oscal-content/blob/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_MODERATE-baseline_profile.json (read November 2, 2026).↩︎