Commit baa83f9
authored
Guard: ignore stale maintainer reactions when content is edited after endorsement (#4228)
Maintainer reactions were treated as evergreen endorsements, even if an
issue/PR/comment was edited after the reaction was added. This allowed
post-endorsement content mutation to retain `approved` integrity.
- **Stale endorsement detection in reaction evaluation**
- Updated `has_maintainer_reaction_with_callback()` to compare item and
reaction timestamps.
- If `item.updatedAt`/`updated_at` is newer than reaction
`createdAt`/`created_at`, that reaction is ignored for integrity
promotion/demotion.
- Timestamp extraction supports both camelCase and snake_case payload
variants already seen in guard inputs.
- **Observability for skipped reactions**
- Added debug logging when a reaction is skipped as stale, including
reactor, reaction type, and compared timestamps.
- **Coverage for timestamp edge cases**
- Added focused unit tests for:
- unmodified item + endorsement (counts)
- item edited after endorsement (ignored)
- endorsement after latest edit (counts)
- mixed stale and fresh reactions (fresh still counts)
- missing timestamps (preserves prior behavior)
```rust
if let (Some(item_updated), Some(reaction_created)) = (item_updated_at, reaction_created_at) {
if item_updated > reaction_created {
// stale endorsement/disapproval: content changed after reaction
continue;
}
}
```
> [!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-build4228467833/b509/launcher.test
/tmp/go-build4228467833/b509/launcher.test
-test.testlogfile=/tmp/go-build4228467833/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 1.0.9/bool.go
1.0.9/bool_func.go x_amd64/vet --gdwarf-5 ut-2993393641.c -o x_amd64/vet
1043�� g_.a -trimpath x_amd64/vet -p go-sdk/internal/-atomic
-lang=go1.24 x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3552295474/b513/launcher.test
/tmp/go-build3552295474/b513/launcher.test
-test.testlogfile=/tmp/go-build3552295474/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build4228467833/b491/config.test
/tmp/go-build4228467833/b491/config.test
-test.testlogfile=/tmp/go-build4228467833/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
@v1.1.3/cpu/arm/arm.go 1043343/b166/ x_amd64/vet --gdwarf-5 backoff -o
x_amd64/vet 1043�� g_.a 1043343/b166/ x_amd64/vet -p 64 -lang=go1.24
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3552295474/b495/config.test
/tmp/go-build3552295474/b495/config.test
-test.testlogfile=/tmp/go-build3552295474/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 1043��
/tmp/go-build212/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/degit
-goversion bin/rustc -c=4 -nolocalimports -importcfg bin/rustc /tmp��
/home/REDACTED/go//home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/de/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
/home/REDACTED/go//home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/de/tmp/go-build4250267068/b498/vet.cfg
.cfg /endpointshardingit 777.build_scriptpush 777.dq1kj865068v-v
-guard/target/deorigin` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build4228467833/b509/launcher.test
/tmp/go-build4228467833/b509/launcher.test
-test.testlogfile=/tmp/go-build4228467833/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 1.0.9/bool.go
1.0.9/bool_func.go x_amd64/vet --gdwarf-5 ut-2993393641.c -o x_amd64/vet
1043�� g_.a -trimpath x_amd64/vet -p go-sdk/internal/-atomic
-lang=go1.24 x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3552295474/b513/launcher.test
/tmp/go-build3552295474/b513/launcher.test
-test.testlogfile=/tmp/go-build3552295474/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build4228467833/b509/launcher.test
/tmp/go-build4228467833/b509/launcher.test
-test.testlogfile=/tmp/go-build4228467833/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 1.0.9/bool.go
1.0.9/bool_func.go x_amd64/vet --gdwarf-5 ut-2993393641.c -o x_amd64/vet
1043�� g_.a -trimpath x_amd64/vet -p go-sdk/internal/-atomic
-lang=go1.24 x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3552295474/b513/launcher.test
/tmp/go-build3552295474/b513/launcher.test
-test.testlogfile=/tmp/go-build3552295474/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build4228467833/b518/mcp.test
/tmp/go-build4228467833/b518/mcp.test
-test.testlogfile=/tmp/go-build4228467833/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
om/tetratelabs/w-errorsas om/tetratelabs/w-ifaceassert x_amd64/vet .
--gdwarf2 --64 x_amd64/vet .cfg�� 1043343/b261/_pkg_.a
/tmp/go-build2121043343/b298/ x_amd64/vet .
telabs/wazero/in/usr/bin/runc --64 x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3552295474/b522/mcp.test
/tmp/go-build3552295474/b522/mcp.test
-test.testlogfile=/tmp/go-build3552295474/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s lib/��
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
lib/rustlib/x86_bash lib/rustlib/x86_/usr/bin/runc
lib/rustlib/x86_--version 05ed-cgu.00.rcgu.o 05ed�� 05ed-cgu.02.rcgu.o
05ed-cgu.03.rcgu.o 05ed-cgu.04.rcgu.o 05ed-cgu.05.rcgubash
05ed-cgu.06.rcgu/usr/bin/runc 05ed-cgu.07.rcgu--version
05ed-cgu.08.rcgu.o` (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>1 file changed
Lines changed: 123 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
467 | 467 | | |
468 | 468 | | |
469 | 469 | | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
470 | 478 | | |
471 | 479 | | |
472 | 480 | | |
| |||
490 | 498 | | |
491 | 499 | | |
492 | 500 | | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
493 | 521 | | |
494 | 522 | | |
495 | 523 | | |
| |||
2008 | 2036 | | |
2009 | 2037 | | |
2010 | 2038 | | |
| 2039 | + | |
| 2040 | + | |
| 2041 | + | |
| 2042 | + | |
| 2043 | + | |
| 2044 | + | |
| 2045 | + | |
| 2046 | + | |
| 2047 | + | |
| 2048 | + | |
| 2049 | + | |
| 2050 | + | |
| 2051 | + | |
| 2052 | + | |
| 2053 | + | |
| 2054 | + | |
| 2055 | + | |
| 2056 | + | |
| 2057 | + | |
| 2058 | + | |
| 2059 | + | |
| 2060 | + | |
| 2061 | + | |
| 2062 | + | |
| 2063 | + | |
| 2064 | + | |
| 2065 | + | |
| 2066 | + | |
| 2067 | + | |
| 2068 | + | |
| 2069 | + | |
| 2070 | + | |
| 2071 | + | |
| 2072 | + | |
| 2073 | + | |
| 2074 | + | |
| 2075 | + | |
| 2076 | + | |
| 2077 | + | |
| 2078 | + | |
| 2079 | + | |
| 2080 | + | |
| 2081 | + | |
| 2082 | + | |
| 2083 | + | |
| 2084 | + | |
| 2085 | + | |
| 2086 | + | |
| 2087 | + | |
| 2088 | + | |
| 2089 | + | |
| 2090 | + | |
| 2091 | + | |
| 2092 | + | |
| 2093 | + | |
| 2094 | + | |
| 2095 | + | |
| 2096 | + | |
| 2097 | + | |
| 2098 | + | |
| 2099 | + | |
| 2100 | + | |
| 2101 | + | |
| 2102 | + | |
| 2103 | + | |
| 2104 | + | |
| 2105 | + | |
| 2106 | + | |
| 2107 | + | |
| 2108 | + | |
| 2109 | + | |
| 2110 | + | |
| 2111 | + | |
| 2112 | + | |
| 2113 | + | |
| 2114 | + | |
| 2115 | + | |
| 2116 | + | |
| 2117 | + | |
| 2118 | + | |
| 2119 | + | |
| 2120 | + | |
| 2121 | + | |
| 2122 | + | |
| 2123 | + | |
| 2124 | + | |
| 2125 | + | |
| 2126 | + | |
| 2127 | + | |
| 2128 | + | |
| 2129 | + | |
| 2130 | + | |
| 2131 | + | |
| 2132 | + | |
| 2133 | + | |
2011 | 2134 | | |
2012 | 2135 | | |
2013 | 2136 | | |
| |||
0 commit comments