README.md #2

  • //
  • p4sudo/
  • dev/
  • doc/
  • broker-rewrite-reference/
  • README.md
  • Markdown
  • View
  • Commits
  • Open Download .zip Download (6 KB)

p4broker REWRITE Feature — Reference and Examples

This directory contains reference files from the Perforce CBD (Component Based Development) project, used here as concrete examples of the p4broker REWRITE feature that P4Sudo is built on.

Source: https://workshop.perforce.com/projects/perforce-software-cbd License: Perforce Consulting Services Agreement (original); included here for reference under open-source terms of the CBD project.


Files

File Description
p4broker.cfg CBD broker config — shows the action = filter; execute = ... pattern
wssync.sh Tiny shell wrapper that invokes wssync.py
wssync.py Main broker entry point — shows how to read broker stdin and call logic
Cbd.py Full CBD implementation — shows REWRITE/PASS/REJECT output format

The business logic in Cbd.py is specific to CBD (component-based sync path rewriting) and is not relevant to P4Sudo. What matters is the protocol it demonstrates.


The Broker Filter Script Protocol

Broker Config Pattern

command: ^(sudo)$
{
    action  = filter;
    execute = "/p4/common/site/p4sudo/p4sudo.sh";
}
  • action = filter — intercept the command and call the script
  • execute — absolute path to the filter script
  • The command regex matches the p4 command name (not including p4 itself)

Input: What the Script Receives on stdin

The broker injects command context as name: value lines on stdin:

command: sudo
workspace: alice.workstation
cwd: /home/alice/myproject
brokerTargetPort: ssl:ppn-p4d-01:1666
argCount: 3
Arg0: mkblackbelt
Arg1: AcmeCorp
Arg2: --dry-run
Field Description
command The p4 command being intercepted (e.g. sudo)
workspace The user's active client workspace name
cwd User's current working directory (local OS syntax, may be Windows or Unix)
brokerTargetPort The p4d port the broker forwards to
argCount Number of arguments that follow
Arg0…ArgN Command arguments, zero-indexed

Additional fields available (from broker documentation and Tom Tyler, 2026): user (P4USER), clientIp (user's IP address).

Parsing pattern (Python):

import sys, re

vals = {}
for line in sys.stdin.readlines():
    m = re.match(r"^(.+?):\s+(.+)$", line)
    if m:
        vals[m.group(1)] = m.group(2)

command   = vals['command']
workspace = vals['workspace']
cwd       = vals['cwd']
p4port    = vals['brokerTargetPort']
arg_count = int(vals['argCount'])
args      = [vals['Arg' + str(i)] for i in range(arg_count)]

Parsing pattern (bash):

while IFS=': ' read -r key value; do
    case "$key" in
        command)         CMD="$value" ;;
        workspace)       WORKSPACE="$value" ;;
        cwd)             CWD="$value" ;;
        brokerTargetPort) P4PORT="$value" ;;
        argCount)        ARG_COUNT="$value" ;;
        Arg*)            ARGS+=("$value") ;;
    esac
done < /dev/stdin

Output: What the Script Writes to stdout

The script's stdout controls what happens next. All output is buffered and returned to the user at once — there is no streaming/incremental feedback.

PASS — Forward the original command to p4d unchanged

action: PASS

REJECT — Deny with an error message shown to the user

action: REJECT
message: You are not authorized to run 'p4 sudo mkblackbelt'.

REWRITE — Execute different command(s) against p4d instead

action: REWRITE
command: sync
arg: //ComponentA/...@2053
arg: //ComponentB/...@9876

Multiple REWRITE blocks can be emitted sequentially to execute multiple commands as the result of a single intercepted command.

Custom output (no action directive)

For commands that p4d doesn't know about (like p4 sudo), the script can simply print text to stdout without an action: directive. That text is returned directly to the p4 client as the command's output. This is the primary mechanism for P4Sudo: the script does its work, prints status/results, and exits.


Key Constraints (Broker Tips)

  1. No interactive prompts. The script must complete its task and return output exactly once per invocation. You cannot prompt the user for additional input mid-execution. All needed information must come from the command arguments or the broker-injected stdin fields.

  2. All output arrives at once. The user sees no scrolling progress text while the script runs. All stdout is buffered and delivered together when the script exits. For long-running operations, design accordingly (e.g. write progress to a log file, return a summary at the end).

  3. Script must be executable and reachable by the p4broker process user. Use absolute paths in the broker config execute directive.

  4. The broker config regex matches the command name only — not p4 itself. ^(sudo)$ matches p4 sudo ....


How P4Sudo Uses This

P4Sudo intercepts p4 sudo <subcmd> <args> and routes to a dispatcher script:

command: ^(sudo)$
{
    action  = filter;
    execute = "/p4/common/site/p4sudo/p4sudo.sh";
}

The dispatcher (p4sudo.sh) reads the broker stdin to get the authenticated user and arguments, checks authorization against p4sudo.cfg, and either dispatches to the appropriate command script or rejects with an error.

Because sudo is not a native p4d command, the script handles everything itself and prints results to stdout. No REWRITE to p4d is needed (though individual command scripts may run p4 commands internally using the service account).

p4 help sudo interception uses a separate broker rule:

command: ^(help)$
{
    action  = filter;
    execute = "/p4/common/site/p4sudo/p4sudo-help.sh";
}

The help script checks if the argument is sudo (or sudo <subcommand>) and returns the P4Sudo help text. For any other p4 help topic, it emits action: PASS to let p4d handle it normally.

# p4broker REWRITE Feature — Reference and Examples

This directory contains reference files from the Perforce CBD (Component Based
Development) project, used here as concrete examples of the p4broker REWRITE
feature that P4Sudo is built on.

**Source:** https://workshop.perforce.com/projects/perforce-software-cbd
**License:** Perforce Consulting Services Agreement (original); included here
for reference under open-source terms of the CBD project.

---

## Files

| File | Description |
|------|-------------|
| `p4broker.cfg` | CBD broker config — shows the `action = filter; execute = ...` pattern |
| `wssync.sh` | Tiny shell wrapper that invokes `wssync.py` |
| `wssync.py` | Main broker entry point — shows how to read broker stdin and call logic |
| `Cbd.py` | Full CBD implementation — shows REWRITE/PASS/REJECT output format |

The business logic in `Cbd.py` is specific to CBD (component-based sync path
rewriting) and is not relevant to P4Sudo. What matters is the protocol it
demonstrates.

---

## The Broker Filter Script Protocol

### Broker Config Pattern

```
command: ^(sudo)$
{
    action  = filter;
    execute = "/p4/common/site/p4sudo/p4sudo.sh";
}
```

- `action = filter` — intercept the command and call the script
- `execute` — absolute path to the filter script
- The command regex matches the p4 command name (not including `p4` itself)

### Input: What the Script Receives on stdin

The broker injects command context as `name: value` lines on stdin:

```
command: sudo
workspace: alice.workstation
cwd: /home/alice/myproject
brokerTargetPort: ssl:ppn-p4d-01:1666
argCount: 3
Arg0: mkblackbelt
Arg1: AcmeCorp
Arg2: --dry-run
```

| Field | Description |
|-------|-------------|
| `command` | The p4 command being intercepted (e.g. `sudo`) |
| `workspace` | The user's active client workspace name |
| `cwd` | User's current working directory (local OS syntax, may be Windows or Unix) |
| `brokerTargetPort` | The p4d port the broker forwards to |
| `argCount` | Number of arguments that follow |
| `Arg0`…`ArgN` | Command arguments, zero-indexed |

Additional fields available (from broker documentation and Tom Tyler, 2026):
`user` (P4USER), `clientIp` (user's IP address).

**Parsing pattern (Python):**
```python
import sys, re

vals = {}
for line in sys.stdin.readlines():
    m = re.match(r"^(.+?):\s+(.+)$", line)
    if m:
        vals[m.group(1)] = m.group(2)

command   = vals['command']
workspace = vals['workspace']
cwd       = vals['cwd']
p4port    = vals['brokerTargetPort']
arg_count = int(vals['argCount'])
args      = [vals['Arg' + str(i)] for i in range(arg_count)]
```

**Parsing pattern (bash):**
```bash
while IFS=': ' read -r key value; do
    case "$key" in
        command)         CMD="$value" ;;
        workspace)       WORKSPACE="$value" ;;
        cwd)             CWD="$value" ;;
        brokerTargetPort) P4PORT="$value" ;;
        argCount)        ARG_COUNT="$value" ;;
        Arg*)            ARGS+=("$value") ;;
    esac
done < /dev/stdin
```

### Output: What the Script Writes to stdout

The script's stdout controls what happens next. All output is buffered and
returned to the user at once — there is no streaming/incremental feedback.

#### PASS — Forward the original command to p4d unchanged

```
action: PASS
```

#### REJECT — Deny with an error message shown to the user

```
action: REJECT
message: You are not authorized to run 'p4 sudo mkblackbelt'.
```

#### REWRITE — Execute different command(s) against p4d instead

```
action: REWRITE
command: sync
arg: //ComponentA/...@2053
arg: //ComponentB/...@9876
```

Multiple REWRITE blocks can be emitted sequentially to execute multiple
commands as the result of a single intercepted command.

#### Custom output (no action directive)

For commands that p4d doesn't know about (like `p4 sudo`), the script can
simply print text to stdout without an `action:` directive. That text is
returned directly to the p4 client as the command's output. This is the
primary mechanism for P4Sudo: the script does its work, prints status/results,
and exits.

---

## Key Constraints (Broker Tips)

1. **No interactive prompts.** The script must complete its task and return
   output exactly once per invocation. You cannot prompt the user for
   additional input mid-execution. All needed information must come from
   the command arguments or the broker-injected stdin fields.

2. **All output arrives at once.** The user sees no scrolling progress text
   while the script runs. All stdout is buffered and delivered together when
   the script exits. For long-running operations, design accordingly (e.g.
   write progress to a log file, return a summary at the end).

3. **Script must be executable and reachable** by the p4broker process user.
   Use absolute paths in the broker config `execute` directive.

4. **The broker config regex matches the command name only** — not `p4` itself.
   `^(sudo)$` matches `p4 sudo ...`.

---

## How P4Sudo Uses This

P4Sudo intercepts `p4 sudo <subcmd> <args>` and routes to a dispatcher script:

```
command: ^(sudo)$
{
    action  = filter;
    execute = "/p4/common/site/p4sudo/p4sudo.sh";
}
```

The dispatcher (`p4sudo.sh`) reads the broker stdin to get the authenticated
user and arguments, checks authorization against `p4sudo.cfg`, and either
dispatches to the appropriate command script or rejects with an error.

Because `sudo` is not a native p4d command, the script handles everything
itself and prints results to stdout. No REWRITE to p4d is needed (though
individual command scripts may run p4 commands internally using the service
account).

`p4 help sudo` interception uses a separate broker rule:

```
command: ^(help)$
{
    action  = filter;
    execute = "/p4/common/site/p4sudo/p4sudo-help.sh";
}
```

The help script checks if the argument is `sudo` (or `sudo <subcommand>`)
and returns the P4Sudo help text. For any other `p4 help` topic, it emits
`action: PASS` to let p4d handle it normally.
# Change User Description Committed
#2 32553 C. Thomas Tyler Added LICENSE file.

  Adjusted URLs replacing https://swarm.workshop with https://workshop
  Adusted path to LICENSE to refer to P4Sudo's own project license, not the SDP one.
#1 32530 bot_Claude_Anthropic Add broker REWRITE reference files; governance CLAUDE.md; session-002 handoff

Add doc/broker-rewrite-reference/ with CBD project examples illustrating
the p4broker REWRITE feature: broker config, wssync.py entry point,
and Cbd.py implementation, plus a README summarizing the filter script
protocol (stdin fields, PASS/REJECT/REWRITE output format).

Rewrite ai/CLAUDE.md as durable governance document covering server
topology, DLP notes, workspace patterns, bot ticket management,
and P4Sudo dev architecture.

Add ai/session-002-handoff.md.

#review-32531 @robert_cowham @tom_tyler