-rollback FeatureDate: 2026-04-08
Author: Claude (Sonnet 4.6), acting on behalf of Tom Tyler
Status: Ready for QA
P4 Location: //guest/tom_tyler/sw/main/SSO_Cutover/
SSO_Cutover.sh is a production script that migrates a Perforce server's human users from
LDAP-managed authentication to the Perforce Authentication Service (P4AS), enabling Single
Sign-On (SSO). The script was built, tested, and verified by the customer in a
copy-of-production sandbox at v1.1.4.
After that acceptance test, the customer requested a rollback capability — a way to reverse all cutover changes in an emergency without manually editing ~1000 user records. This is the feature added in v2.0.0.
A new -rollback option was added to SSO_Cutover.sh. It reverses, in a single command,
everything the forward cutover run changed — but only what it actually changed.
During a live (-y) forward run, the script now records what it did using p4 key
entries:
| Key | Meaning |
|---|---|
SSO_Cutover.chg.auth.sso.allow.passwd |
Phase 1 set this configurable |
SSO_Cutover.chg.auth.sso.nonldap |
Phase 1 set this configurable |
SSO_Cutover.chg.auth.default.method |
Phase 1 set this configurable |
SSO_Cutover.chg.extension |
Phase 2 updated the P4AS extension |
SSO_Cutover.chg.trigger |
Phase 3 added the SSO_default trigger |
SSO_Cutover.ldap.0.<username> |
Phase 4 changed this user's AuthMethod from ldap→perforce |
Phase 2 also saves the original extension config to a file:
$LOGS/SSO_Cutover.extension_backup.p4s
| Rollback Phase | Action |
|---|---|
| Phase 1 | configure unset for each changed configurable; reverts auth.default.method to ldap |
| Phase 2 | Restores the P4AS extension from the backup file |
| Phase 3 | Removes SSO_default entries from the Triggers table |
| Phase 4 | Sets AuthMethod=ldap for each user tracked by a SSO_Cutover.ldap.0.* key |
After a successful live rollback, all tracking keys are deleted (clean slate).
-rollback requires -y to actually do anything (dry run by default, same as forward run)-g is not allowed with -rollback (group is not needed; user set comes from keys)-nc, -ne, -nt, -nu are not allowed with -rollback (rollback is automatic)Use a P4 Battle School Workshop training lab instance. These labs have a realistic training data set that can be adapted for this purpose.
The lab needs to be in the state the script expects to find at the start of a forward run:
P4AS Extension installed in opt-in mode
The extension (Auth::loginhook, name loginhook-a1) must exist and be configured with
a small set of SSO opt-in users/groups (simulating the pilot phase). The rollback will
need to restore this opt-in config, so it must exist and be saved as the baseline.
Configurables at pre-SSO values
auth.sso.allow.passwd — should be 0 or unset auth.sso.nonldap — should be 0 or unset auth.default.method — should be ldapSSO_default trigger absent
The SSO_default trigger should not yet be in the Triggers table.
A mix of user AuthMethod values
AuthMethod: ldap (these should be changed by forward run and restored
by rollback)AuthMethod: perforce already (the simulated pilot/opt-in users — these
should be left alone by rollback since SSO_Cutover.ldap.0.<user> won't be set
for them)A Non-SSO exempt group
Create a group (e.g. Non-SSO) containing at least the perforce super user and any
simulated automation/robot accounts.
SDP layout
The script sources /p4/common/bin/p4_vars. The lab must have a working SDP layout,
or the relevant variables (P4BIN, LOGS, P4TMP, etc.) must be set in the
environment. $LOGS must be a writable directory — this is where the extension backup
file lands.
Run all tests first as a dry run (no -y) to verify the preview output looks correct,
then repeat as a live run (-y) to verify actual changes.
SSO_Cutover.sh -g Non-SSO -y
Verify after:
p4 configure show auth.sso.allow.passwd → 1p4 configure show auth.sso.nonldap → 1p4 configure show auth.default.method → perforcep4 extension --configure Auth::loginhook --name loginhook-a1 -o → opt-out mode
(non-sso-groups: Non-SSO, non-sso-users: perforce, sso-groups/sso-users: none)p4 triggers -o → SSO_default entries presentp4 -ztag -F "%User% %AuthMethod%" users → all non-exempt users show perforcep4 keys -e "SSO_Cutover.*" → tracking keys present$LOGS/SSO_Cutover.extension_backup.p4s → file exists and contains valid opt-in configSSO_Cutover.sh -rollback
Verify:
NO_OP: prefixesSSO_Cutover.sh -rollback -y
Verify after:
p4 configure show auth.sso.allow.passwd → 0 or unset (original state)p4 configure show auth.sso.nonldap → 0 or unsetp4 configure show auth.default.method → ldapp4 triggers -o → SSO_default entries goneldapperforce before the forward run → still perforce (untouched)p4 keys -e "SSO_Cutover.*" → all tracking keys deletedRun rollback a second time immediately after Test 3.
Verify:
Run forward with -ne (skip extension processing):
SSO_Cutover.sh -g Non-SSO -ne -y
Then run rollback:
SSO_Cutover.sh -rollback -y
Verify:
SSO_Cutover.sh -rollback -g Non-SSO # -g not allowed with -rollback
SSO_Cutover.sh -rollback -nc # phase-skip not allowed with -rollback
SSO_Cutover.sh -rollback -ne
SSO_Cutover.sh -rollback -nt
SSO_Cutover.sh -rollback -nu
Verify: Each prints a usage error and exits with code 2.
Attempt rollback on a clean instance with no SSO_Cutover.* keys:
SSO_Cutover.sh -rollback -y
Verify:
After a forward run, delete the extension backup file, then attempt rollback:
rm "$LOGS/SSO_Cutover.extension_backup.p4s"
SSO_Cutover.sh -rollback -y
Verify:
| File | Description |
|---|---|
SSO_Cutover.sh |
The script (v2.0.0) |
SSO_Cutover.command_summary.txt |
Output of SSO_Cutover.sh -man; regenerated for v2.0.0 |
TestUtility-ResetToBaseline.sh |
Pre-existing reset utility (lab only); does not have the rollback precision of the new -rollback option |
p4_vars:
P4BIN, P4USER, LOGS, P4TMP.NoOp=0 (i.e., SSO_Cutover.0.<user> and
SSO_Cutover.ldap.0.<user>). Dry-run keys (SSO_Cutover.1.*) are also cleaned
up by rollback but don't gate any rollback logic.TestUtility-ResetToBaseline.sh can be used between test iterations to
reset lab state, but note it resets all users (not just those tracked by the script)
and requires the BASELINE.extension.p4s file to exist. It is complementary to, not
a replacement for, the new -rollback option.# QA Handoff: SSO_Cutover.sh v2.0.0 — `-rollback` Feature
**Date:** 2026-04-08
**Author:** Claude (Sonnet 4.6), acting on behalf of Tom Tyler
**Status:** Ready for QA
**P4 Location:** `//guest/tom_tyler/sw/main/SSO_Cutover/`
---
## Background
`SSO_Cutover.sh` is a production script that migrates a Perforce server's human users from
LDAP-managed authentication to the Perforce Authentication Service (P4AS), enabling Single
Sign-On (SSO). The script was built, tested, and verified by the customer in a
copy-of-production sandbox at v1.1.4.
After that acceptance test, the customer requested a rollback capability — a way to reverse
all cutover changes in an emergency without manually editing ~1000 user records. This is the
feature added in v2.0.0.
---
## What Changed in v2.0.0
A new `-rollback` option was added to `SSO_Cutover.sh`. It reverses, in a single command,
everything the forward cutover run changed — but only what it actually changed.
### How tracking works
During a **live** (`-y`) forward run, the script now records what it did using `p4 key`
entries:
| Key | Meaning |
|-----|---------|
| `SSO_Cutover.chg.auth.sso.allow.passwd` | Phase 1 set this configurable |
| `SSO_Cutover.chg.auth.sso.nonldap` | Phase 1 set this configurable |
| `SSO_Cutover.chg.auth.default.method` | Phase 1 set this configurable |
| `SSO_Cutover.chg.extension` | Phase 2 updated the P4AS extension |
| `SSO_Cutover.chg.trigger` | Phase 3 added the SSO_default trigger |
| `SSO_Cutover.ldap.0.<username>` | Phase 4 changed this user's AuthMethod from ldap→perforce |
Phase 2 also saves the original extension config to a file:
`$LOGS/SSO_Cutover.extension_backup.p4s`
### What rollback reverses
| Rollback Phase | Action |
|----------------|--------|
| Phase 1 | `configure unset` for each changed configurable; reverts `auth.default.method` to `ldap` |
| Phase 2 | Restores the P4AS extension from the backup file |
| Phase 3 | Removes `SSO_default` entries from the Triggers table |
| Phase 4 | Sets `AuthMethod=ldap` for each user tracked by a `SSO_Cutover.ldap.0.*` key |
After a successful live rollback, all tracking keys are deleted (clean slate).
### Rollback constraints (enforced by the script)
- `-rollback` **requires** `-y` to actually do anything (dry run by default, same as forward run)
- `-g` is **not allowed** with `-rollback` (group is not needed; user set comes from keys)
- `-nc`, `-ne`, `-nt`, `-nu` are **not allowed** with `-rollback` (rollback is automatic)
- Passwords set during the forward run **cannot** be restored — this is acceptable for this
customer because human users authenticate via LDAP and are unaffected by the P4 database
password
---
## Proposed Test Environment
Use a **P4 Battle School Workshop** training lab instance. These labs have a realistic training
data set that can be adapted for this purpose.
### Required data setup (simulate pre-cutover state)
The lab needs to be in the state the script expects to find at the *start* of a forward run:
1. **P4AS Extension installed** in opt-in mode
The extension (`Auth::loginhook`, name `loginhook-a1`) must exist and be configured with
a small set of SSO opt-in users/groups (simulating the pilot phase). The rollback will
need to restore this opt-in config, so it must exist and be saved as the baseline.
2. **Configurables at pre-SSO values**
- `auth.sso.allow.passwd` — should be `0` or unset
- `auth.sso.nonldap` — should be `0` or unset
- `auth.default.method` — should be `ldap`
3. **SSO_default trigger absent**
The `SSO_default` trigger should not yet be in the Triggers table.
4. **A mix of user AuthMethod values**
- Most users: `AuthMethod: ldap` (these should be changed by forward run and restored
by rollback)
- A handful: `AuthMethod: perforce` already (the simulated pilot/opt-in users — these
should be left alone by rollback since `SSO_Cutover.ldap.0.<user>` won't be set
for them)
5. **A Non-SSO exempt group**
Create a group (e.g. `Non-SSO`) containing at least the `perforce` super user and any
simulated automation/robot accounts.
6. **SDP layout**
The script sources `/p4/common/bin/p4_vars`. The lab must have a working SDP layout,
or the relevant variables (`P4BIN`, `LOGS`, `P4TMP`, etc.) must be set in the
environment. `$LOGS` must be a writable directory — this is where the extension backup
file lands.
---
## Test Plan
Run all tests first as a **dry run** (no `-y`) to verify the preview output looks correct,
then repeat as a **live run** (`-y`) to verify actual changes.
### Test 1 — Happy path: forward run
```bash
SSO_Cutover.sh -g Non-SSO -y
```
**Verify after:**
- `p4 configure show auth.sso.allow.passwd` → `1`
- `p4 configure show auth.sso.nonldap` → `1`
- `p4 configure show auth.default.method` → `perforce`
- `p4 extension --configure Auth::loginhook --name loginhook-a1 -o` → opt-out mode
(non-sso-groups: Non-SSO, non-sso-users: perforce, sso-groups/sso-users: none)
- `p4 triggers -o` → `SSO_default` entries present
- `p4 -ztag -F "%User% %AuthMethod%" users` → all non-exempt users show `perforce`
- `p4 keys -e "SSO_Cutover.*"` → tracking keys present
- `$LOGS/SSO_Cutover.extension_backup.p4s` → file exists and contains valid opt-in config
### Test 2 — Happy path: rollback dry run
```bash
SSO_Cutover.sh -rollback
```
**Verify:**
- Output describes what would be reversed with `NO_OP:` prefixes
- No actual changes made (configurables, extension, triggers, users all unchanged)
- Tracking keys still present
### Test 3 — Happy path: rollback live run
```bash
SSO_Cutover.sh -rollback -y
```
**Verify after:**
- `p4 configure show auth.sso.allow.passwd` → `0` or unset (original state)
- `p4 configure show auth.sso.nonldap` → `0` or unset
- `p4 configure show auth.default.method` → `ldap`
- Extension back in opt-in mode (diff against original opt-in config)
- `p4 triggers -o` → `SSO_default` entries gone
- Users whose AuthMethod was changed → back to `ldap`
- Users already on `perforce` before the forward run → still `perforce` (untouched)
- `p4 keys -e "SSO_Cutover.*"` → all tracking keys deleted
### Test 4 — Idempotency: double rollback
Run rollback a second time immediately after Test 3.
**Verify:**
- Script runs without errors
- Output says each phase has nothing to undo ("was not changed by the SSO cutover; skipping")
- Exit code 0
### Test 5 — Partial forward run (phase skipped)
Run forward with `-ne` (skip extension processing):
```bash
SSO_Cutover.sh -g Non-SSO -ne -y
```
Then run rollback:
```bash
SSO_Cutover.sh -rollback -y
```
**Verify:**
- Rollback Phase 2 reports "P4AS extension was not changed by the SSO cutover; skipping"
- Extension is NOT touched by rollback
- Configurables, triggers, and users are properly rolled back
### Test 6 — Invalid option combinations (should all fail with usage errors)
```bash
SSO_Cutover.sh -rollback -g Non-SSO # -g not allowed with -rollback
SSO_Cutover.sh -rollback -nc # phase-skip not allowed with -rollback
SSO_Cutover.sh -rollback -ne
SSO_Cutover.sh -rollback -nt
SSO_Cutover.sh -rollback -nu
```
**Verify:** Each prints a usage error and exits with code 2.
### Test 7 — Rollback with no prior forward run
Attempt rollback on a clean instance with no `SSO_Cutover.*` keys:
```bash
SSO_Cutover.sh -rollback -y
```
**Verify:**
- Script runs without errors
- All phases report "was not changed by the SSO cutover; skipping"
- Exit code 0
### Test 8 — Missing extension backup file
After a forward run, delete the extension backup file, then attempt rollback:
```bash
rm "$LOGS/SSO_Cutover.extension_backup.p4s"
SSO_Cutover.sh -rollback -y
```
**Verify:**
- Rollback Phase 2 reports an error: "Extension backup file not found"
- Other phases (1, 3, 4) still complete successfully
- Exit code reflects 1 error
---
## Files
| File | Description |
|------|-------------|
| `SSO_Cutover.sh` | The script (v2.0.0) |
| `SSO_Cutover.command_summary.txt` | Output of `SSO_Cutover.sh -man`; regenerated for v2.0.0 |
| `TestUtility-ResetToBaseline.sh` | Pre-existing reset utility (lab only); does not have the rollback precision of the new `-rollback` option |
---
## Notes for the Testing Agent
- The script requires an SDP environment. Key variables sourced from `p4_vars`:
`P4BIN`, `P4USER`, `LOGS`, `P4TMP`.
- ShellCheck passes cleanly on the v2.0.0 script.
- The forward-run tracking keys use `NoOp=0` (i.e., `SSO_Cutover.0.<user>` and
`SSO_Cutover.ldap.0.<user>`). Dry-run keys (`SSO_Cutover.1.*`) are also cleaned
up by rollback but don't gate any rollback logic.
- The existing `TestUtility-ResetToBaseline.sh` can be used between test iterations to
reset lab state, but note it resets *all* users (not just those tracked by the script)
and requires the `BASELINE.extension.p4s` file to exist. It is complementary to, not
a replacement for, the new `-rollback` option.
- After each live rollback test, re-run the forward cutover to restore SSO state before
the next rollback test.
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 32545 | C. Thomas Tyler | Add QA handoff notes for SSO_Cutover.sh v2.0.0 -rollback feature |