@plainconceptsplatform/workflows 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/loops/actions/classify-route/classify-route.sh +2 -2
- package/loops/docs/diagrams.md +7 -7
- package/loops/templates/ci/app-ci-dotnet-next.yml +3 -0
- package/loops/templates/ci/app-ci-node-monorepo.yml +3 -0
- package/loops/workflows/agent-triage.md +3 -5
- package/loops/workflows/work-router.yml +7 -46
- package/package.json +1 -1
|
@@ -43,8 +43,8 @@ classify_route() {
|
|
|
43
43
|
if has_label refine || has_label implement; then
|
|
44
44
|
error="issue opened with a work label; triage skipped"
|
|
45
45
|
else
|
|
46
|
-
# Issue opened by
|
|
47
|
-
# gates the caller on is_outside_collaborator; this routes unconditionally
|
|
46
|
+
# Issue opened by a read-only outside collaborator → triage. The authorize
|
|
47
|
+
# job gates the caller on is_outside_collaborator; this routes unconditionally
|
|
48
48
|
# so write+ openers classify to triage but the caller job skips them.
|
|
49
49
|
route="triage"
|
|
50
50
|
triage_mode="first"
|
package/loops/docs/diagrams.md
CHANGED
|
@@ -37,9 +37,9 @@ without touching the others.
|
|
|
37
37
|
flowchart TD
|
|
38
38
|
ev{"One GitHub event"} --> classify
|
|
39
39
|
classify["classify (rung 1)<br/>pure shell, no network<br/>one event in, one route out"] --> authorize
|
|
40
|
-
authorize{"authorize (rung 1)<br/>Write permission,
|
|
40
|
+
authorize{"authorize (rung 1)<br/>Write permission, or<br/>read only?"}
|
|
41
41
|
authorize -->|"human, trusted"| work
|
|
42
|
-
authorize -->|"
|
|
42
|
+
authorize -->|"read only"| triageOnly
|
|
43
43
|
authorize -.->|"no permission"| idle
|
|
44
44
|
work{"route"} -->|refine| wRefine
|
|
45
45
|
work -->|implement| wImpl
|
|
@@ -79,7 +79,7 @@ fewer events, not adding more guards.
|
|
|
79
79
|
```mermaid
|
|
80
80
|
flowchart LR
|
|
81
81
|
open("Issue opened") --> triage
|
|
82
|
-
triage{"triage<br/>
|
|
82
|
+
triage{"triage<br/>read-only opener"} -->|pass| refine
|
|
83
83
|
triage -.->|block| closed(("Closed"))
|
|
84
84
|
triage -.->|needs-info| author("Author replies") --> triage
|
|
85
85
|
write("Write+ user<br/>self-labels") --> refine
|
|
@@ -114,9 +114,9 @@ instead of one pull request that has to fix them all.
|
|
|
114
114
|
|
|
115
115
|
## agent-triage.md
|
|
116
116
|
|
|
117
|
-
The front door for issues opened
|
|
118
|
-
|
|
119
|
-
collaborator goes through it
|
|
117
|
+
The front door for issues opened by people with read-only access. The gate is permission level, not
|
|
118
|
+
membership: anybody with write skips triage and self-labels into the pipeline, org member or not, while
|
|
119
|
+
a read-only outside collaborator goes through it.
|
|
120
120
|
|
|
121
121
|
Four outcomes, and only one of them closes anything. `needs-maintainer` is the one worth knowing: the
|
|
122
122
|
request is legitimate but addressed to the wrong intake, so the issue stays open with `review` and a
|
|
@@ -125,7 +125,7 @@ maintainer takes it on by adding `refine`.
|
|
|
125
125
|
```mermaid
|
|
126
126
|
flowchart TD
|
|
127
127
|
triStart("Work Router<br/>triage route") --> triPick
|
|
128
|
-
triPick{"Opened by
|
|
128
|
+
triPick{"Opened by a read-only<br/>outside collaborator?"} -->|yes| triReserve
|
|
129
129
|
triPick -.->|"no, write+ user"| triIdle
|
|
130
130
|
triReserve("Reserve (rung 4)<br/>bot-working + triage") --> triFacts
|
|
131
131
|
triFacts("Facts (rung 3)<br/>Issue, comments and every open<br/>issue written to disk") --> triRound
|
|
@@ -276,6 +276,9 @@ jobs:
|
|
|
276
276
|
with:
|
|
277
277
|
format: cyclonedx-json
|
|
278
278
|
artifact-name: ${{ env.SBOM_ARTIFACT_NAME }}
|
|
279
|
+
# On a tag that already has a GitHub Release the action attaches the SBOM to it, which
|
|
280
|
+
# needs contents: write this workflow does not have, and fails the run that gates deploy.
|
|
281
|
+
upload-release-assets: false
|
|
279
282
|
|
|
280
283
|
# A bot pull request is opened with GITHUB_TOKEN, and GitHub delivers no workflow_run event
|
|
281
284
|
# for the CI runs that follow (the run's actor is the bot). The router's CI-completion route
|
|
@@ -206,6 +206,9 @@ jobs:
|
|
|
206
206
|
with:
|
|
207
207
|
format: cyclonedx-json
|
|
208
208
|
artifact-name: ${{ env.SBOM_ARTIFACT_NAME }}
|
|
209
|
+
# On a tag that already has a GitHub Release the action attaches the SBOM to it, which
|
|
210
|
+
# needs contents: write this workflow does not have, and fails the run that gates deploy.
|
|
211
|
+
upload-release-assets: false
|
|
209
212
|
|
|
210
213
|
# A bot pull request is opened with GITHUB_TOKEN, and GitHub delivers no workflow_run event
|
|
211
214
|
# for the CI runs that follow (the run's actor is the bot). The router's CI-completion route
|
|
@@ -54,11 +54,9 @@ description: |
|
|
|
54
54
|
cannot be done, is a security risk, is too dangerous, or is still ambiguous after
|
|
55
55
|
three rounds.
|
|
56
56
|
|
|
57
|
-
The gate is
|
|
58
|
-
is_outside_collaborator for read permission
|
|
59
|
-
|
|
60
|
-
organisation's own. An org member with write skips triage; an outside collaborator
|
|
61
|
-
with write does not.
|
|
57
|
+
The gate is permission level, not organisation membership. The authorize job sets
|
|
58
|
+
is_outside_collaborator for read permission only. Anybody with write or better skips
|
|
59
|
+
triage, org member or not: an outside collaborator given write is a colleague.
|
|
62
60
|
|
|
63
61
|
Router-only worker: triggered exclusively via workflow_call from work-router.yml.
|
|
64
62
|
Contract inputs: issue-number, mode(first|retriage).
|
|
@@ -287,11 +287,6 @@ jobs:
|
|
|
287
287
|
GH_TOKEN: ${{ github.token }}
|
|
288
288
|
ACTOR: ${{ github.actor }}
|
|
289
289
|
EVENT: ${{ github.event_name }}
|
|
290
|
-
# Who GitHub says this person is relative to the repository, straight from the
|
|
291
|
-
# payload. OWNER and MEMBER are the organisation's own; COLLABORATOR is repository
|
|
292
|
-
# access without organisation membership, which is what triage is for. Read from
|
|
293
|
-
# here because a repository-scoped GITHUB_TOKEN cannot query org membership.
|
|
294
|
-
AUTHOR_ASSOCIATION: ${{ github.event.issue.author_association || github.event.comment.author_association || github.event.pull_request.author_association }}
|
|
295
290
|
run: |
|
|
296
291
|
set -euo pipefail
|
|
297
292
|
|
|
@@ -320,48 +315,14 @@ jobs:
|
|
|
320
315
|
permission=$(gh api "repos/$GITHUB_REPOSITORY/collaborators/$ACTOR/permission" \
|
|
321
316
|
--jq '.permission' 2>/dev/null || echo "none")
|
|
322
317
|
|
|
323
|
-
# Is this person one of the organisation's own, or somebody with repository access
|
|
324
|
-
# from outside it? Triage exists for the second kind.
|
|
325
|
-
#
|
|
326
|
-
# The payload answers it. The org API cannot: `orgs/{org}/members/{user}` needs an
|
|
327
|
-
# org-scoped token and GITHUB_TOKEN is scoped to this repository, so that call failed
|
|
328
|
-
# for everybody and every admin who opened an issue was declared an outside
|
|
329
|
-
# collaborator and triaged. It is kept only as a fallback for events that carry no
|
|
330
|
-
# association, and it can no longer decide "outside" on its own.
|
|
331
|
-
org=$(echo "$GITHUB_REPOSITORY" | cut -d/ -f1)
|
|
332
|
-
case "${AUTHOR_ASSOCIATION:-}" in
|
|
333
|
-
OWNER | MEMBER)
|
|
334
|
-
is_member=true
|
|
335
|
-
;;
|
|
336
|
-
COLLABORATOR)
|
|
337
|
-
is_member=false
|
|
338
|
-
;;
|
|
339
|
-
*)
|
|
340
|
-
# No association in this payload. Ask the org, and believe a yes rather than a
|
|
341
|
-
# no: a failed call here is indistinguishable from a real non-member.
|
|
342
|
-
if gh api "orgs/$org/members/$ACTOR" >/dev/null 2>&1; then
|
|
343
|
-
is_member=true
|
|
344
|
-
else
|
|
345
|
-
is_member=unknown
|
|
346
|
-
fi
|
|
347
|
-
;;
|
|
348
|
-
esac
|
|
349
|
-
|
|
350
318
|
case "$permission" in
|
|
351
319
|
admin | maintain | write)
|
|
352
|
-
#
|
|
353
|
-
#
|
|
354
|
-
#
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
echo "is_outside_collaborator=false" >> "$GITHUB_OUTPUT"
|
|
359
|
-
echo "::notice::$ACTOR has $permission permission and is an org member."
|
|
360
|
-
else
|
|
361
|
-
echo "trusted=true" >> "$GITHUB_OUTPUT"
|
|
362
|
-
echo "is_outside_collaborator=true" >> "$GITHUB_OUTPUT"
|
|
363
|
-
echo "::notice::$ACTOR has $permission permission but is NOT an org member (outside collaborator). Triage route eligible."
|
|
364
|
-
fi
|
|
320
|
+
# Write or better is a colleague, org member or not: an outside collaborator who
|
|
321
|
+
# was given write is somebody the team chose to work with, and triaging what they
|
|
322
|
+
# open starts an agent nobody asked for. Only read access is the outside door.
|
|
323
|
+
echo "trusted=true" >> "$GITHUB_OUTPUT"
|
|
324
|
+
echo "is_outside_collaborator=false" >> "$GITHUB_OUTPUT"
|
|
325
|
+
echo "::notice::$ACTOR has $permission permission."
|
|
365
326
|
;;
|
|
366
327
|
read)
|
|
367
328
|
echo "trusted=false" >> "$GITHUB_OUTPUT"
|
|
@@ -553,7 +514,7 @@ jobs:
|
|
|
553
514
|
|
|
554
515
|
call-triage:
|
|
555
516
|
needs: [classify, authorize]
|
|
556
|
-
# Triage on issue open is for outside collaborators only (handled by dispatch-triage).
|
|
517
|
+
# Triage on issue open is for read-only outside collaborators only (handled by dispatch-triage).
|
|
557
518
|
# A trusted actor who opens an issue should not start triage - they can add refine/implement/direct
|
|
558
519
|
# labels or manually dispatch triage. All other triage routes (labeled, comment, dispatch) are trusted.
|
|
559
520
|
if: needs.classify.outputs.route == 'triage' && needs.authorize.outputs.trusted == 'true' && !(github.event_name == 'issues' && github.event.action == 'opened')
|