Skip to main content
This is not an official U.S. federal government website. The Federal Modernization Workbook is independent technical analysis. It does not represent the position of, and has not been reviewed or endorsed by, any federal agency.

Training module · Draft

Ticket-to-Machine, Module 1: The Loop and the Typed Task

Where the kit sits in Book 13’s five-step loop, and how to check the identity finding before it reaches ServiceNow

Research draft: Module 1 of the Ticket-to-Machine learning path. You map the kit’s files to the loop’s five steps, learn the identity finding’s data contract, and validate payloads on a laptop with finding_contract.py. Guide Gate 4; workbook Chapter 01.
Modified

November 1, 2026

Status — Draft

This page is still being written. Expect gaps and changes; it is not part of the workbook's production guidance. Last reviewed 2026-11-09.

Learning path: Ticket-to-Machine on ServiceNow and SailPoint · Module 1 of 7 · 50 minutes · Guide Gate 4 · Workbook Chapter 01

Watch: the narrated deck for this module: Deck · ▶ Watch (about 14 minutes, captions) · MP4 · Script · Captions.

Unit 1: Introduction

3 minutes, with the objectives and prerequisites

Your agency’s service desk closes an access ticket when a technician types “done.” Nobody can say who owned the drift, when it fell due, or what the account should look like afterward. Book 13’s answer is a typed task: one record with a class, a severity, an owner, a clock and an intended state that a later re-read can check. Every step of the loop writes or reads that record, so you start with it.

The federal requirement. Gate 4 turns findings and requests into documented, owned, clocked records. The guide’s Gate 4 requirements and evidence table maps it to NIST SP 800-53 CM-3, RA-7, CA-7 and AC-5, and the chapter’s federal requirements and evidence says what the contract check proves and who keeps it. Each table’s KSI column names the FedRAMP 20x Key Security Indicators to line your evidence up with; your cloud providers report against them, the agency doesn’t.

Learning objectives

In this module, you’ll:

  • Explain the loop’s five steps and name the kit file for each step that has one, and the step that has none.
  • Describe the fields of the identity finding’s data contract and what each one is for.
  • Validate a finding payload on a laptop and predict whether ServiceNow accepts, rejects or de-duplicates it, and when it falls due.
  • Recognize an intended state that gives the re-read nothing to check.

Prerequisites

Unit 2: The loop, and where the kit sits

8 minutes

The loop has five steps: test, detect drift, raise a typed task, actuate on the native surface, and close with evidence. The kit has three builds in Pass 1 that cover four of them and leaves actuation to a later pass. Read these, in order:

  1. Book 13, Appendix B: the coordination loop, for the five steps.
  2. Chapter 01: the loop, and where the kit sits, for the table that maps each step to a kit file and a chapter.
  3. The guide’s loop at a glance, for the products that do each step, and the four gaps between the products and the loop.

As you read, note which step has no code in Pass 1. You’ll meet it again in Module 6.

Unit 3: The identity finding and its contract

10 minutes

The Scripted REST resource inside ServiceNow enforces the finding’s contract: it validates the payload, maps severity to a priority and a due date on the program’s tempo, de-duplicates against an active finding, and derives an intended state when the payload has none. Until Chapter 01, nothing outside ServiceNow applied the same rules, so a client learned a payload was wrong only from a 400 on a live instance.

finding_contract.py applies those rules on a laptop, and a test keeps its constants in step with the script. Read:

Unit 4: Exercise: Lab 1 (fixtures, no tenant)

22 minutes

NoteEvery command in Lab 1

Every command in this lab, in order, from examples/servicenow-sailpoint. Each step below says what it does and what to look for.

# Step 1
python -m pytest tests/python/test_finding_contract.py -q

# Step 2
python clients/python/finding_contract.py --validate tests/fixtures/payloads/samples.json --now 2026-11-01T12:00:00Z

# Step 3
node --test tests/servicenow/servicenow_scripts.test.js

# Step 4
python clients/python/identity_drift.py --hr-csv tests/fixtures/hr_extract.csv --config tests/fixtures/config.fixtures.json --graph-users-json tests/fixtures/graph_users.json --isc-identities-json tests/fixtures/isc_identities.json --isc-accounts-json tests/fixtures/isc_uncorrelated_accounts.json --entra-audit-json tests/fixtures/entra_audit.json --out-json out/day1.json --out-csv out/day1.csv
python clients/python/finding_contract.py --from-drift out/day1.json --now 2026-11-01T12:00:00Z

# Step 5
rm -rf out

You check payloads the way the Scripted REST resource would, then check every payload the drift client would post. Work in examples/servicenow-sailpoint. The chapter’s Lab 1 explains each result.

  1. Run the chapter’s tests.

    python -m pytest tests/python/test_finding_contract.py -q

    Expected: 26 passed.

  2. Check five sample payloads.

    python clients/python/finding_contract.py --validate tests/fixtures/payloads/samples.json --now 2026-11-01T12:00:00Z

    Expected output (the command exits 1, because two payloads would be rejected):

    sample-1-good: ok stale_access P2 priority 2 due 2026-11-01T13:00:00Z system entra_user
    sample-2-typo: 400 drift_class must be one of missing_identity, stale_access, orphan_account, attribute_drift, unauthorized_write, credential_drift, schema_drift
    sample-3-empty-intent: ok unauthorized_write P2 priority 2 due 2026-11-01T13:00:00Z system isc_account
    sample-3-empty-intent: warning: intended_state names nothing a re-read can check (expected: Book 13 routes this class to a person, who sets it)
    sample-4-bad-severity: 400 severity must be P1, P2, P3 or P4
    sample-5-closure: ok closure_signal (moves matches to Awaiting verification; never closes)
    3 accepted, 2 rejected, 0 would de-duplicate
  3. Run the ServiceNow script’s own tests, the rules the Python mirrors.

    node --test tests/servicenow/servicenow_scripts.test.js

    Expected: tests 15, pass 15, fail 0.

  4. Run the drift reconciliation over the fixtures, then check the payloads it would post.

    python clients/python/identity_drift.py --hr-csv tests/fixtures/hr_extract.csv --config tests/fixtures/config.fixtures.json --graph-users-json tests/fixtures/graph_users.json --isc-identities-json tests/fixtures/isc_identities.json --isc-accounts-json tests/fixtures/isc_uncorrelated_accounts.json --entra-audit-json tests/fixtures/entra_audit.json --out-json out/day1.json --out-csv out/day1.csv
    python clients/python/finding_contract.py --from-drift out/day1.json --now 2026-11-01T12:00:00Z

    Expected: twelve lines start ok, three carry the warning (two missing identities and the unauthorized write), and the last line is 12 accepted, 0 rejected, 0 would de-duplicate.

  5. Delete the out folder.

    rm -rf out

Check your work: for any payload, you can say what the Scripted REST resource will do with it.

Unit 5: Exercise: Lab 2 (your test instance)

Not timed. Not run by the authors.

In a ServiceNow Personal Developer Instance, never production, you build the finding table and the Scripted REST resource, lock it down with a REST_Endpoint ACL, post a payload you checked in Lab 1, and confirm the de-duplication and the 400. Follow Chapter 01, Lab 2.

  • You need: a Personal Developer Instance, and the web_service_admin role to create the Scripted REST API.
  • Back it out: step 5 of the chapter’s Lab 2 deletes the test records, the ACL, the role, the API and the scoped application.

Unit 6: Knowledge check

5 minutes

  1. A payload has drift_class set to stale_access and no severity. What does the Scripted REST resource do?
    1. Rejects it with a 400, because severity is required.
    2. Accepts it as P4, with a 72-hour window.
    3. Accepts it with the class default, P2, and a one-hour window.
  2. An intended state is {"attributes": {}, "entitlements_absent": []}. Why does finding_contract.py warn about it?
    1. ServiceNow rejects an empty object with a 400.
    2. It looks present, but a re-read finds no difference against it and would close the record on nothing.
    3. It makes the finding de-duplicate against every other finding for the subject.
  3. What does a closure_signal payload do to matching findings?
    1. Closes them.
    2. Moves them to Awaiting verification; it never closes them.
    3. Reopens them for the owner to review.
  4. Which loop step has no code in the kit’s Pass 1?
    1. Raise a typed task.
    2. Actuate on the native surface.
    3. Close with evidence.
  1. c. The script defaults severity by class, and sample 1 got P2 with a one-hour window. See Chapter 01, Lab 1.
  2. b. A non-empty object can still name nothing checkable. See is_checkable in what this chapter adds.
  3. b. A signal moves matches to Awaiting verification; only a re-read closes. See sample 5 in Chapter 01, Lab 1.
  4. b. No Pass 1 code writes to Entra ID, Active Directory or ISC. See the loop, and where the kit sits.

Unit 7: Summary

2 minutes

You mapped the kit to the loop, read the finding’s contract, and checked payloads on a laptop the way ServiceNow will, including every payload the drift client would post.

Evidence an ISSO keeps from this module: the ServiceNow finding records and the contract tests in the repository; each record’s due date, which Module 7 measures. The chapter’s federal requirements and evidence lists them; before shipping, work through its checklist.

Back to top