Jeremy BryantCybersecurity portfolio

Offline security exercise / source reading

Reconcile joiner, mover and leaver access

Read the supplied instructions here, then download the complete project to use the Python utilities and training materials. These are guided practice materials; reference checks do not assess independent understanding.

Download complete source ZIP

Archive folder: jeremy-bryant-pages/labs/identity-lifecycle/

Lab instructions

labs/identity-lifecycle/README.md

# Reconcile joiner, mover and leaver access

Turn a dated staffing change into an access delta. Preserve legitimate new duties, remove stale access, and explain why an approved handover exception ends at a specific date.

**Time:** 30-45 minutes for a first pass; use the later recall task on another day.
**Prerequisites:** Basic file navigation, editing a small JSON worksheet, and introductory networking/security vocabulary. No professional security experience, cloud account, coding background or programming changes are required.

> **Vocabulary:** **Joiner**: someone starting a role. **Mover**: someone changing duties. **Leaver**: someone whose access must end. **Entitlement**: one named access item. **Delta**: the difference between current and target access. **Exception**: a limited, approved departure from the normal target.

## Evidence and exact semantics

`data` has `as_of` (`YYYY-MM-DD`) and nonempty `people`. Each person has
`id`, `event` (`joiner`, `mover`, `leaver`), `effective_on`, `current`, `required`,
and `exceptions`. Access lists contain unique lowercase labels. An exception
has exactly `access`, `approved_by`, and `expires_on`. Only movers can have
exceptions; each must name existing access that is absent from `required`, have
a nonempty approver ID, and expire on or after the move date. Leavers must have
empty `required` and no exceptions. Invalid dates and unknown fields fail.

Dates are whole UTC days. An event is due when `effective_on <= as_of`.
Exception expiry is inclusive: an exception expiring on the review day remains
valid through that day. Here "active-exceptions" means unexpired exceptions;
they contribute to the target only when the move is due.

| Situation | Target access |
| --- | --- |
| Due joiner | Required access. |
| Due mover | Required access plus unexpired handover exceptions. |
| Due leaver | Empty. |
| Future joiner | Empty; early access is proposed for removal. |
| Future mover or leaver | Current access; the future event is deferred. |

For each person use the exact decision syntax
`add:ITEMS;remove:ITEMS;retain:ITEMS`. Each `ITEMS` is a comma-separated,
alphabetically sorted list with no spaces, or the literal `none`. The three
sets are `target - current`, `current - target`, and `current intersection target`.
For example, `add:new-queue;remove:old-queue;retain:mail` is valid syntax.
The reserved output word `none` means an empty set, not an entitlement.

## Run the exercise

From the repository root, enter this folder with `cd labs/identity-lifecycle`.
Use Python 3.10 or newer. On Windows, `py` may replace `python` if that is your
installed launcher. No package install, account, cloud subscription or billing
setup is needed. Commands run entirely offline and change no real service.

```text
python lab.py cases
python lab.py prepare --scenario guided --out run/attempt-01
python lab.py show --case run/attempt-01/case.json
```

Read the case and any extracted `.txt` evidence. Edit the blank
`run/attempt-01/answers.json`: fill every decision with the exact vocabulary
below, write your own explanation, and cite record IDs or line references in
`evidence`. Keep `notes.txt` for prediction, uncertainty and help used.
Only after saving your prediction:

```text
python lab.py analyse --case run/attempt-01/case.json
python lab.py check --case run/attempt-01/case.json --answers run/attempt-01/answers.json
python test_lab.py
python lab.py verify
```

The worksheet has exactly `decisions` (object), `explanation` (text), and
`evidence` (list of text references). For example, an evidence entry can be a
record ID plus its field name. Use your own case IDs, not invented references.
`check` compares decision strings and requires nonempty written fields; a person
must assess their accuracy. `verify` checks shipped fixtures, not learner skill.
Exit codes are 0 for success/match, 1 for differences or incomplete written
fields, and 2 for invalid input. Default `--case` is the guided fixture beside
the script. Explicit input paths are relative to the working directory; `--out`
is relative to this lab and must be a new folder below `run/`.

For the next cases, prepare fresh folders:

```text
python lab.py prepare --scenario changed --out run/attempt-02
python lab.py prepare --scenario challenge --out run/attempt-03
```

Replace `attempt-01` in `show`, `analyse` and `check` with the chosen folder.
Edit practice copies only. Do not overwrite fixture or reference files.

## Deliverable and handover

Save one completed worksheet and a short evidence note for each case. Include
your prediction, changed judgment, uncertainty, and one next check you cannot
perform from this evidence. Record whether you used the worked example or help.
Ask a reviewer: "Can you reproduce my decision from these record IDs, and which
claim goes beyond the evidence?" Your independent status remains **unassessed**;
matching output is not a qualification, professional experience or proof of
mastery. These are original fictional practice cases, not assessment submissions.

## Limits

This fictional policy does not implement directory changes, approval authenticity, sessions, access inherited through groups, account disablement, leave of absence, emergency termination or asset ownership transfer. A future mover keeps current access in this bounded model; separate baseline violations would need another review.

## Primary references

The official overview distinguishes joiner, mover and leaver processes and time-based conditions. The set operations and inclusive exception rule here are explicit fictional practice policy.

- [Microsoft: lifecycle workflows](https://learn.microsoft.com/en-us/entra/id-governance/what-are-lifecycle-workflows)

Links are optional further reading, checked 2026-10-23. Running this lab does
not fetch them. See [the worked example](WORKED-EXAMPLE.md) after your prediction
and [the drills](DRILLS.md) for varied practice.

Worked example

labs/identity-lifecycle/WORKED-EXAMPLE.md

# Worked example: Reconcile joiner, mover and leaver access

Open this after saving a prediction for the guided case. The reference explains
these fictional records; it does not assess your independent performance.

1. `as_of` is `2026-10-23`. Compare this date with each `effective_on` before
   doing any set arithmetic. All three guided events are due.
2. `new-starter` currently has nothing and requires `mail` and `casework`.
   Target is `{casework, mail}`: use
   `add:casework,mail;remove:none;retain:none`.
3. `team-move` took effect on `2026-10-22`. Required access is `{mail,
   new-queue}`. `old-reports` has an approved exception through `2026-10-23`,
   so today's target is `{mail, new-queue, old-reports}`. `old-queue` has no
   exception. Use `add:new-queue;remove:old-queue;retain:mail,old-reports`.
   Removing everything from the old role would incorrectly remove mail and
   the authorised handover; adding only the new queue would leave stale access.
4. `departed` leaves today, so target is empty. Use
   `add:none;remove:casework,mail;retain:none`. The result is an access proposal,
   not confirmation that sessions or credentials have been revoked.

In a handover, cite `team-move.exceptions[0].expires_on` and state that a review
on the next day must remove `old-reports` unless new authorised evidence exists.

After comparison, keep your original prediction and add a correction in
`notes.txt`. State the evidence that changed your judgment. Copying the answer
without reconstructing the evidence leaves independent understanding unassessed.

Practice drills

labs/identity-lifecycle/DRILLS.md

# Practice progression: Reconcile joiner, mover and leaver access

Use the exact prepare/show/check commands in [README.md](README.md). Save a
prediction before running `analyse`. Fresh folders preserve earlier attempts.

1. **Guided (10 minutes):** draw current, required and exception sets for all
   guided records. Save your deltas before opening the worked example.
2. **With prompts (5 minutes):** Is the event effective yet? Does each exception
   name old access? Does it expire today or before today? Which access must stay?
3. **Independent (10 minutes):** use `challenge`. Preserve `future-mover`'s
   present duties, remove `late-leaver` access, and finish `partial-mover`'s new
   duties without deleting the new queue already granted.
4. **Changed evidence (5 minutes):** use `changed`. Explain why the same
   `old-reports` exception no longer applies. Why is early joiner access removed
   while future leaver access remains? In a practice copy move `as_of` to
   `2026-10-25` and predict both changes before running the analysis.
5. **Teach back (5 minutes):** explain why a mover review needs both additions
   and removals. Identify two offboarding tasks outside this entitlement model.
6. **Later recall (next day, 5 minutes):** write the three set formulas and the
   expiry boundary without notes. Rebuild the team-move delta from the fixture.

For each pass record: evidence references, decision, reason, uncertainty, help
used and one next check. Have another person review the explanation and one
unfamiliar case if possible. Until that occurs, independent completion is
unassessed even if every decision matches. Keep all attempts below `run/`.

Browse all 30 lab source pages