Commit 662a784
authored
Add built-in promotion and demotion labels to GitHub guard (#4899)
Adds two optional, opt-in policy fields that let operators promote or
demote content item integrity via GitHub labels — a more auditable
alternative to reactions since only triage+ users can add labels.
## Policy fields
| Field | JSON key | Default | Effect |
|---|---|---|---|
| `promotion_label` | `"promotion-label"` | `""` (disabled) | Raises
integrity to `approved` when label is present |
| `demotion_label` | `"demotion-label"` | `""` (disabled) | Caps
integrity at `none` when label is present |
Example policy JSON:
```json
{
"promotion-label": "agent-approved",
"demotion-label": "agent-blocked"
}
```
## Evaluation order
Updated `apply_post_integrity_adjustments` chain:
1. `approval-labels` promotion (existing)
2. **Built-in promotion label** ← new
3. Endorsement reactions (existing)
4. **Built-in demotion label** ← new (overrides steps 1–3)
5. Disapproval reactions (existing; lower result wins against step 4)
6. `blocked-users` (unconditional, unchanged)
## Changes
- **`helpers.rs`**: New `promotion_label`/`demotion_label` fields on
`PolicyContext`; `has_promotion_label`, `has_demotion_label` public
helpers; `apply_promotion_label_promotion`,
`apply_demotion_label_demotion` internal functions wired into the
adjustment pipeline
- **`lib.rs`**: `AllowOnlyPolicy` gains `promotion-label` and
`demotion-label` serde fields, threaded into `PolicyContext`
construction in `label_agent`
- **`mod.rs`**: Re-exports new helpers; ~20 unit tests covering
detection, case-insensitivity, precedence (demotion overrides promotion
and `approval-labels`; `blocked-users` still wins unconditionally)
> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build533781863/b513/launcher.test
/tmp/go-build533781863/b513/launcher.test
-test.testlogfile=/tmp/go-build533781863/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build533781863/b413/vet.cfg
1.80.0/internal/resolver/delegatingresolver/delegatingresolver.go -I
x_amd64/vet --gdwarf-5 nal/encoding/def-atomic -o x_amd64/vet -I g_.a
64/src/runtime/t-ifaceassert x_amd64/vet --gdwarf-5
ernal/middleware-atomic -o x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build533781863/b495/config.test
/tmp/go-build533781863/b495/config.test
-test.testlogfile=/tmp/go-build533781863/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build533781863/b368/vet.cfg
1.80.0/internal/resolver/dns/dns_resolver.go
aw-mcpg/internal/sys/docker.go x_amd64/vet --gdwarf-5 --64 -o
x_amd64/vet -I g_.a -I x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet` (dns
block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build533781863/b513/launcher.test
/tmp/go-build533781863/b513/launcher.test
-test.testlogfile=/tmp/go-build533781863/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build533781863/b413/vet.cfg
1.80.0/internal/resolver/delegatingresolver/delegatingresolver.go -I
x_amd64/vet --gdwarf-5 nal/encoding/def-atomic -o x_amd64/vet -I g_.a
64/src/runtime/t-ifaceassert x_amd64/vet --gdwarf-5
ernal/middleware-atomic -o x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build533781863/b513/launcher.test
/tmp/go-build533781863/b513/launcher.test
-test.testlogfile=/tmp/go-build533781863/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build533781863/b413/vet.cfg
1.80.0/internal/resolver/delegatingresolver/delegatingresolver.go -I
x_amd64/vet --gdwarf-5 nal/encoding/def-atomic -o x_amd64/vet -I g_.a
64/src/runtime/t-ifaceassert x_amd64/vet --gdwarf-5
ernal/middleware-atomic -o x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build533781863/b522/mcp.test
/tmp/go-build533781863/b522/mcp.test
-test.testlogfile=/tmp/go-build533781863/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -W .cfg
/tmp/go-build141-ifaceassert x_amd64/vet . --gdwarf2 --64 x_amd64/vet
.cfg�� 1358588/b392/_pkg_.a -I x_amd64/vet --gdwarf-5
g/protobuf/inter--version -o x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>3 files changed
Lines changed: 368 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
145 | 145 | | |
146 | 146 | | |
147 | 147 | | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
148 | 157 | | |
149 | 158 | | |
150 | 159 | | |
| |||
352 | 361 | | |
353 | 362 | | |
354 | 363 | | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
355 | 435 | | |
356 | 436 | | |
357 | 437 | | |
| |||
1431 | 1511 | | |
1432 | 1512 | | |
1433 | 1513 | | |
1434 | | - | |
1435 | | - | |
1436 | | - | |
| 1514 | + | |
| 1515 | + | |
| 1516 | + | |
| 1517 | + | |
| 1518 | + | |
1437 | 1519 | | |
1438 | 1520 | | |
1439 | 1521 | | |
| |||
1443 | 1525 | | |
1444 | 1526 | | |
1445 | 1527 | | |
| 1528 | + | |
| 1529 | + | |
1446 | 1530 | | |
1447 | 1531 | | |
| 1532 | + | |
| 1533 | + | |
1448 | 1534 | | |
1449 | 1535 | | |
1450 | 1536 | | |
| |||
0 commit comments