@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.
@@ -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 an outside collaborator → triage. The authorize job
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"
@@ -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, and is the<br/>actor one of the org's own?"}
40
+ authorize{"authorize (rung 1)<br/>Write permission, or<br/>read only?"}
41
41
  authorize -->|"human, trusted"| work
42
- authorize -->|"outside collaborator"| triageOnly
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/>outside collaborator"} -->|pass| refine
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 from outside the organisation. The gate is membership, not permission
118
- level: an org member with write skips triage and self-labels into the pipeline, while an outside
119
- collaborator goes through it even when they hold write.
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 an<br/>outside collaborator?"} -->|yes| triReserve
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 organisation membership, not permission level. The authorize job sets
58
- is_outside_collaborator for read permission, and also for write or better when the
59
- author association is COLLABORATOR repository access without being one of the
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
- # "unknown" counts as inside. Somebody with write or better whose membership
353
- # cannot be established is far more likely to be a colleague than an outside
354
- # collaborator, and treating them as outside starts a triage agent nobody asked
355
- # for - which, with a four-hour timeout, holds a runner for the afternoon.
356
- if [ "$is_member" != "false" ]; then
357
- echo "trusted=true" >> "$GITHUB_OUTPUT"
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')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plainconceptsplatform/workflows",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Install and update Platform GitHub agentic workflows.",
5
5
  "keywords": [
6
6
  "github-actions",