Skip to content

fix: implement decline applicant flow#253

Open
frank0277 wants to merge 2 commits into
boundlessfi:mainfrom
frank0277:fix/decline-applicant-flow
Open

fix: implement decline applicant flow#253
frank0277 wants to merge 2 commits into
boundlessfi:mainfrom
frank0277:fix/decline-applicant-flow

Conversation

@frank0277
Copy link
Copy Markdown

@frank0277 frank0277 commented May 29, 2026

Implements the applicant decline flow on the application review dashboard.

Added useDeclineApplicant mutation
Added Decline button beside Select on each application card
Added confirmation dialog with optional decline reason
Optimistically removes declined applicants from the review queue
Rolls back local dashboard state on decline failure
Removes declined applicants from comparison mode
Closes #208

Summary by CodeRabbit

  • New Features

    • Added applicant decline flow with a "Decline" button, confirmation dialog, and optional reason input
    • Application counts, empty states, and displayed cards update automatically; comparison filtering preserved
  • Bug Fixes

    • Fixed a stability issue that could cause the review dashboard to crash during use
  • Chores

    • CI workflow environment handling adjusted for schema checks

Review Change Stack

@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2026

@uche102 is attempting to deploy a commit to the Threadflow Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented May 29, 2026

@frank0277 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

📝 Walkthrough

Walkthrough

Adds an applicant-decline flow: dashboard UI (Decline button + AlertDialog with optional reason), optimistic useDeclineApplicant mutation that marks applications DECLINED and removes them from cached lists with rollback on error, plus CI workflow env token wiring.

Changes

Applicant decline flow

Layer / File(s) Summary
Decline applicant mutation hook
hooks/use-bounty-application.ts
New useDeclineApplicant hook implements optimistic cache updates: marks applications as DECLINED with timestamp and reason, removes declined applicants from bounty.applications, restores prior cache on error, and invalidates related queries on settle.
Dashboard imports and state sync
components/bounty/application-review-dashboard.tsx
Adds Textarea, AlertDialog* components, XCircle icon, and useDeclineApplicant import. Initializes reviewApplications, declineTarget, declineReason and an effect to sync reviewApplications from applications prop.
Decline handler and optimistic UI wiring
components/bounty/application-review-dashboard.tsx
handleDeclineApplicant optimistically removes the applicant from reviewApplications and selectedForCompare, invokes the mutation, clears dialog on success, restores reviewApplications on error, and defines visibleApplications.
Decline button UI
components/bounty/application-review-dashboard.tsx
Renders a red Decline button with XCircle icon on each card; clicking seeds declineTarget and clears the reason input; button disabled while a decline is pending.
Application rendering and confirmation dialog
components/bounty/application-review-dashboard.tsx
Header counts and empty state use visibleApplications.length. Card lists map from visibleApplications in both comparison and non-comparison modes. Adds controlled AlertDialog with Textarea for optional decline reason. Includes a local useEffect stub that throws an error.

CI workflow token wiring

Layer / File(s) Summary
Job-level env and checkout condition
.github/workflows/check-schema.yml
Adds job-level env.BOUNDLESS_NESTJS_TOKEN from secrets and updates steps to reference env.BOUNDLESS_NESTJS_TOKEN for the private canonical schema checkout and conditional messaging; minor node-version string formatting change.

Sequence Diagram

sequenceDiagram
  participant Reviewer
  participant Dashboard
  participant Mutation
  participant Cache

  Reviewer->>Dashboard: Click Decline
  Dashboard->>Dashboard: Open AlertDialog
  Reviewer->>Dashboard: Confirm with optional reason
  Dashboard->>Mutation: handleDeclineApplicant(bountyId, applicant, reason)
  Mutation->>Cache: onMutate: mark DECLINED and remove from applications
  Cache-->>Mutation: onSuccess/onSettled
  Mutation-->>Dashboard: optimistic UI already updated
  Dashboard->>Reviewer: Remove card and show toast
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • boundlessfi/bounties#200: Introduces the application review dashboard and selection infrastructure that this PR builds upon.

Suggested reviewers

  • Benjtalkshow

Poem

🐰 I nibble code and gently hop,
Decline in red, then off they trot.
A reason typed, a dialog done,
Cache updated — one by one.
Hooray! The review queue's lighter now.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes workflow configuration changes to check-schema.yml that are unrelated to the decline applicant flow objective defined in issue #208. Remove the check-schema.yml workflow changes or move them to a separate PR focused on workflow improvements, as they are outside the scope of implementing the decline applicant flow.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: implement decline applicant flow' directly summarizes the main change—implementing the decline applicant flow as specified in the objectives.
Linked Issues check ✅ Passed The PR implements all required coding objectives from issue #208: useDeclineApplicant mutation, Decline button with AlertDialog, optimistic updates with rollback, decline reason recording, and comparison mode handling.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@frank0277 frank0277 force-pushed the fix/decline-applicant-flow branch from 9b0244b to a8e4408 Compare May 29, 2026 03:36
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/bounty/application-review-dashboard.tsx`:
- Around line 67-69: The component is crashing because useEffect is not imported
from React and the local hoisted stub function useEffect (the one that does
`throw new Error("Function not implemented.")` around lines 317-319) is being
called; update the React import to include useEffect (and drop unused useMemo if
appropriate), remove the local stub function named useEffect, and ensure the
effect call inside the component that calls setReviewApplications(applications)
uses the real React useEffect.

In `@hooks/use-bounty-application.ts`:
- Around line 214-231: The current update to prev.bounty.applications maps the
matching application to status "DECLINED" with declineReason/declinedReason and
declinedAt but then immediately chains .filter(...) which removes that declined
record from the cache; remove the chained .filter so the mapped DECLINED
application (with reason and declinedAt) is kept in prev.bounty.applications,
ensuring the declineReason persists in cache (update the code around the
applications mapping that references applicantAddress, reason, and declinedAt in
hooks/use-bounty-application.ts).
- Around line 184-199: useDeclineApplicant’s mutationFn only returns an
optimistic object and there is no persistence path in ApplicationContractClient,
so declined state is not durable; either (A) add a real decline
endpoint/contract and call it from useDeclineApplicant: implement a
declineApplicant(bountyId, applicantAddress, reason) method on
ApplicationContractClient, call that inside mutationFn (or mutationFn should
call the client and return the persisted result), and ensure the backend exposes
bounty.applications so bountyKeys.detail / bountyKeys.lists refetches reflect
the decline, or (B) if backend changes aren’t possible now, remove the fake
persisted declinedAt behavior and instead implement a proper optimistic update
via react-query callbacks (onMutate / onError / onSettled) to update the cached
applications for bountyKeys.detail locally and avoid/invalidate refetches that
would overwrite it; reference useDeclineApplicant, ApplicationContractClient,
bountyKeys.detail, bountyKeys.lists, and getApplications in
components/bounty-detail/bounty-detail-client.tsx when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c58e9020-c495-4081-99eb-28724d2561b0

📥 Commits

Reviewing files that changed from the base of the PR and between c56bd4b and 9b0244b.

📒 Files selected for processing (2)
  • components/bounty/application-review-dashboard.tsx
  • hooks/use-bounty-application.ts

Comment on lines +67 to +69
useEffect(() => {
setReviewApplications(applications);
}, [applications]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: useEffect is not imported — this call hits the throwing stub at Lines 317-319 and crashes the component on every render.

react is imported as { useMemo, useState } (Line 2), so useEffect resolves to the hoisted local function useEffect (Lines 317-319) which does throw new Error("Function not implemented."). The component will throw immediately.

🐛 Proposed fix: import the real `useEffect` and delete the stub

Line 2 (also drops the now-unused useMemo):

-import { useMemo, useState } from "react";
+import { useEffect, useState } from "react";

Lines 317-319:

-function useEffect(arg0: () => void, arg1: Application[][]) {
-  throw new Error("Function not implemented.");
-}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/bounty/application-review-dashboard.tsx` around lines 67 - 69, The
component is crashing because useEffect is not imported from React and the local
hoisted stub function useEffect (the one that does `throw new Error("Function
not implemented.")` around lines 317-319) is being called; update the React
import to include useEffect (and drop unused useMemo if appropriate), remove the
local stub function named useEffect, and ensure the effect call inside the
component that calls setReviewApplications(applications) uses the real React
useEffect.

Comment thread hooks/use-bounty-application.ts
Comment on lines +214 to +231
...prev.bounty,
applications: prev.bounty.applications
.map((application) =>
application.applicantAddress === applicantAddress
? {
...application,
status: "DECLINED",
declineReason: reason?.trim() || undefined,
declinedReason: reason?.trim() || undefined,
declinedAt,
}
: application,
)
.filter(
(application) =>
application.applicantAddress !== applicantAddress,
),
updatedAt: declinedAt,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

.filter() discards the record you just marked DECLINED — the decline reason is never recorded in cache.

The .map() marks the matching application as DECLINED and stores declineReason/declinedReason, but the chained .filter() then removes that exact entry, throwing away all of that work. This violates the requirement to record the decline reason in the cache.

Drop the filter so the declined record (with its reason) persists; the dashboard already removes the applicant from its own visible list.

🐛 Proposed fix: keep the declined record instead of filtering it out
             applications: prev.bounty.applications
               .map((application) =>
                 application.applicantAddress === applicantAddress
                   ? {
                       ...application,
                       status: "DECLINED",
                       declineReason: reason?.trim() || undefined,
                       declinedReason: reason?.trim() || undefined,
                       declinedAt,
                     }
                   : application,
-              )
-              .filter(
-                (application) =>
-                  application.applicantAddress !== applicantAddress,
-              ),
+              ),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
...prev.bounty,
applications: prev.bounty.applications
.map((application) =>
application.applicantAddress === applicantAddress
? {
...application,
status: "DECLINED",
declineReason: reason?.trim() || undefined,
declinedReason: reason?.trim() || undefined,
declinedAt,
}
: application,
)
.filter(
(application) =>
application.applicantAddress !== applicantAddress,
),
updatedAt: declinedAt,
...prev.bounty,
applications: prev.bounty.applications
.map((application) =>
application.applicantAddress === applicantAddress
? {
...application,
status: "DECLINED",
declineReason: reason?.trim() || undefined,
declinedReason: reason?.trim() || undefined,
declinedAt,
}
: application,
),
updatedAt: declinedAt,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hooks/use-bounty-application.ts` around lines 214 - 231, The current update
to prev.bounty.applications maps the matching application to status "DECLINED"
with declineReason/declinedReason and declinedAt but then immediately chains
.filter(...) which removes that declined record from the cache; remove the
chained .filter so the mapped DECLINED application (with reason and declinedAt)
is kept in prev.bounty.applications, ensuring the declineReason persists in
cache (update the code around the applications mapping that references
applicantAddress, reason, and declinedAt in hooks/use-bounty-application.ts).

Copy link
Copy Markdown
Contributor

@Benjtalkshow Benjtalkshow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dashboard crashes at runtime. components/bounty/application-review-dashboard.tsx:67 calls useEffect, but the file only imports useMemo, useState from React. An AI auto-generated a fake stub at lines 317-319 that throws Error: Function not implemented. Build passes because the stub satisfies TypeScript, but the moment the parent passes a new applications prop the effect fires and the page crashes.

Three things to fix:

  1. Import useEffect from React on line 2 and delete the fake stub at the bottom of the file (lines 317-319). Also remove the unused useMemo import. ESLint flags all three as warnings.

  2. hooks/use-bounty-application.ts:221-222 sets both declineReason and declinedReason to the same value. One is a typo. Pick one and delete the other.

  3. The dashboard duplicates state by syncing applications prop into reviewApplications local state. That's what the broken effect was trying to keep in sync. The useDeclineApplicant hook already does the optimistic filter in the React Query cache. Drop the local reviewApplications state entirely and render directly from the prop (which itself comes from the cache via the parent). Single source of truth.

Once those are in this is ready.

@frank0277 frank0277 requested a review from Benjtalkshow May 30, 2026 12:59
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/check-schema.yml:
- Line 18: The workflow uses mutable tags "actions/checkout@v4" and
"actions/setup-node@v4"; update those uses entries to the corresponding full
40-character commit SHAs (replace each "`@v4`" occurrence for checkout and
setup-node with the commit SHA from the respective GitHub Actions repo) so the
CI references an exact immutable revision; ensure you update all occurrences in
the file (both checkout usages and the setup-node usage) and commit the updated
workflow.
- Around line 10-40: The job "check-schema" lacks an explicit permissions block
so it inherits full default GITHUB_TOKEN scopes; add a minimal permissions:
block under the check-schema job to grant only what is required (for example
read-only contents and repo access needed for actions/checkout and any API calls
your script uses) and remove unnecessary scopes; update the job definition
(check-schema) to include a permissions section that restricts permissions to
the least-privilege set required by the workflow.
- Around line 17-18: Update both checkout steps that use actions/checkout@v4 to
set persist-credentials: false so the runner does not persist the token to local
git config; locate the checkout invocations (the steps using
actions/checkout@v4) and add a persist-credentials: false entry under each
step's with: block (ensure YAML indentation is correct).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2bf771a-2fa2-4552-badf-6129061224db

📥 Commits

Reviewing files that changed from the base of the PR and between 9b0244b and 624afde.

📒 Files selected for processing (3)
  • .github/workflows/check-schema.yml
  • components/bounty/application-review-dashboard.tsx
  • hooks/use-bounty-application.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/bounty/application-review-dashboard.tsx

Comment on lines 10 to +40
check-schema:
name: Check schema is in sync
runs-on: ubuntu-latest
env:
BOUNDLESS_NESTJS_TOKEN: ${{ secrets.BOUNDLESS_NESTJS_TOKEN }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Checkout canonical schema repo (private)
if: ${{ secrets.BOUNDLESS_NESTJS_TOKEN != '' }}
if: ${{ env.BOUNDLESS_NESTJS_TOKEN != '' }}
uses: actions/checkout@v4
with:
repository: boundlessfi/boundless-nestjs
path: boundless-nestjs
token: ${{ secrets.BOUNDLESS_NESTJS_TOKEN }}
token: ${{ env.BOUNDLESS_NESTJS_TOKEN }}

- name: Note about private repo
if: ${{ secrets.BOUNDLESS_NESTJS_TOKEN == '' }}
if: ${{ env.BOUNDLESS_NESTJS_TOKEN == '' }}
run: |
echo "No secret BOUNDLESS_NESTJS_TOKEN provided; skipping checkout of private repo."
echo "If the canonical schema is in the private repo, add a repository secret named BOUNDLESS_NESTJS_TOKEN with a PAT that has access to boundlessfi/boundless-nestjs."

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: "20"

- name: Run schema check
run: node ./scripts/sync-schema.js --check
run: node ./scripts/sync-schema.js --check No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify explicit permissions are present in workflow files
rg -n '^\s*permissions\s*:' .github/workflows/*.yml .github/workflows/*.yaml

Repository: boundlessfi/bounties

Length of output: 129


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Workflow files:"
ls -la .github/workflows || true

echo
echo "Searching for explicit job/workflow-level permissions blocks:"
# Only search files that actually exist
for f in $(ls .github/workflows/*.yml 2>/dev/null || true); do
  rg -n '^\s*permissions\s*:' "$f" || true
done
for f in $(ls .github/workflows/*.yaml 2>/dev/null || true); do
  rg -n '^\s*permissions\s*:' "$f" || true
done

echo
echo "=== check-schema.yml (lines 1-120) ==="
nl -ba .github/workflows/check-schema.yml | sed -n '1,120p'

Repository: boundlessfi/bounties

Length of output: 478


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== check-schema.yml (cat -n) ==="
cat -n .github/workflows/check-schema.yml | sed -n '1,140p'

echo
echo "=== ci.yml (permissions search) ==="
rg -n '^\s*permissions\s*:' .github/workflows/ci.yml || true

echo
echo "=== check-schema.yml permissions search ==="
rg -n '^\s*permissions\s*:' .github/workflows/check-schema.yml || true

echo
echo "=== check-schema.yml persist-credentials search ==="
rg -n 'persist-credentials' .github/workflows/check-schema.yml || true

echo
echo "=== check-schema.yml action version pins ==="
rg -n 'uses:\s*actions/(checkout|setup-node)@' .github/workflows/check-schema.yml

Repository: boundlessfi/bounties

Length of output: 1893


Add an explicit least-privilege permissions block.

jobs.check-schema currently has no permissions: block, so the workflow falls back to default GITHUB_TOKEN scopes.

Suggested fix
 jobs:
   check-schema:
     name: Check schema is in sync
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
     env:
       BOUNDLESS_NESTJS_TOKEN: ${{ secrets.BOUNDLESS_NESTJS_TOKEN }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
check-schema:
name: Check schema is in sync
runs-on: ubuntu-latest
env:
BOUNDLESS_NESTJS_TOKEN: ${{ secrets.BOUNDLESS_NESTJS_TOKEN }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Checkout canonical schema repo (private)
if: ${{ secrets.BOUNDLESS_NESTJS_TOKEN != '' }}
if: ${{ env.BOUNDLESS_NESTJS_TOKEN != '' }}
uses: actions/checkout@v4
with:
repository: boundlessfi/boundless-nestjs
path: boundless-nestjs
token: ${{ secrets.BOUNDLESS_NESTJS_TOKEN }}
token: ${{ env.BOUNDLESS_NESTJS_TOKEN }}
- name: Note about private repo
if: ${{ secrets.BOUNDLESS_NESTJS_TOKEN == '' }}
if: ${{ env.BOUNDLESS_NESTJS_TOKEN == '' }}
run: |
echo "No secret BOUNDLESS_NESTJS_TOKEN provided; skipping checkout of private repo."
echo "If the canonical schema is in the private repo, add a repository secret named BOUNDLESS_NESTJS_TOKEN with a PAT that has access to boundlessfi/boundless-nestjs."
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: "20"
- name: Run schema check
run: node ./scripts/sync-schema.js --check
run: node ./scripts/sync-schema.js --check
check-schema:
name: Check schema is in sync
runs-on: ubuntu-latest
permissions:
contents: read
env:
BOUNDLESS_NESTJS_TOKEN: ${{ secrets.BOUNDLESS_NESTJS_TOKEN }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Checkout canonical schema repo (private)
if: ${{ env.BOUNDLESS_NESTJS_TOKEN != '' }}
uses: actions/checkout@v4
with:
repository: boundlessfi/boundless-nestjs
path: boundless-nestjs
token: ${{ env.BOUNDLESS_NESTJS_TOKEN }}
- name: Note about private repo
if: ${{ env.BOUNDLESS_NESTJS_TOKEN == '' }}
run: |
echo "No secret BOUNDLESS_NESTJS_TOKEN provided; skipping checkout of private repo."
echo "If the canonical schema is in the private repo, add a repository secret named BOUNDLESS_NESTJS_TOKEN with a PAT that has access to boundlessfi/boundless-nestjs."
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Run schema check
run: node ./scripts/sync-schema.js --check
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 17-18: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 20-26: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 10-40: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)


[error] 18-18: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 22-22: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 35-35: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/check-schema.yml around lines 10 - 40, The job
"check-schema" lacks an explicit permissions block so it inherits full default
GITHUB_TOKEN scopes; add a minimal permissions: block under the check-schema job
to grant only what is required (for example read-only contents and repo access
needed for actions/checkout and any API calls your script uses) and remove
unnecessary scopes; update the job definition (check-schema) to include a
permissions section that restricts permissions to the least-privilege set
required by the workflow.

Comment on lines 17 to 18
- name: Checkout repository
uses: actions/checkout@v4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect checkout steps and whether persist-credentials is set
rg -n -C3 'uses:\s*actions/checkout@' .github/workflows/*.yml .github/workflows/*.yaml
rg -n 'persist-credentials:\s*false' .github/workflows/*.yml .github/workflows/*.yaml

Repository: boundlessfi/bounties

Length of output: 1670


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Show the relevant section of the workflow with line numbers
nl -ba .github/workflows/check-schema.yml | sed -n '1,120p'

# 2) Search only .yml files for persist-credentials on checkout steps
rg -n -C2 'uses:\s*actions/checkout@' .github/workflows/*.yml
rg -n 'persist-credentials:\s*false' .github/workflows/*.yml || true
rg -n 'persist-credentials:' .github/workflows/*.yml || true

Repository: boundlessfi/bounties

Length of output: 107


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Show the beginning of the workflow with line numbers
cat -n .github/workflows/check-schema.yml | sed -n '1,140p'

# 2) Search only .yml files for persist-credentials on checkout steps
rg -n -C2 'uses:\s*actions/checkout@' .github/workflows/*.yml
rg -n 'persist-credentials:\s*false' .github/workflows/*.yml || true
rg -n 'persist-credentials:' .github/workflows/*.yml || true

Repository: boundlessfi/bounties

Length of output: 2727


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Confirm persist-credentials usage only in check-schema.yml
rg -n 'persist-credentials' .github/workflows/check-schema.yml || true
rg -n -C2 'uses:\s*actions/checkout@' .github/workflows/check-schema.yml

# Reprint the relevant section cleanly
cat -n .github/workflows/check-schema.yml | sed -n '10,40p'

Repository: boundlessfi/bounties

Length of output: 1689


Disable credential persistence on checkout steps in .github/workflows/check-schema.yml.

actions/checkout@v4 should set persist-credentials: false on both checkout steps (lines 17-18 and 20-26) to prevent the token/credentials from being written to the runner’s local git config for subsequent steps.

Suggested fix
       - name: Checkout repository
         uses: actions/checkout@v4
+        with:
+          persist-credentials: false
 
       - name: Checkout canonical schema repo (private)
         if: ${{ env.BOUNDLESS_NESTJS_TOKEN != '' }}
         uses: actions/checkout@v4
         with:
           repository: boundlessfi/boundless-nestjs
           path: boundless-nestjs
           token: ${{ env.BOUNDLESS_NESTJS_TOKEN }}
+          persist-credentials: false
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 17-18: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 18-18: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/check-schema.yml around lines 17 - 18, Update both
checkout steps that use actions/checkout@v4 to set persist-credentials: false so
the runner does not persist the token to local git config; locate the checkout
invocations (the steps using actions/checkout@v4) and add a persist-credentials:
false entry under each step's with: block (ensure YAML indentation is correct).


steps:
- name: Checkout repository
uses: actions/checkout@v4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all workflow `uses:` entries are SHA pinned (40-hex)
rg -n '^\s*uses:\s*[^@]+@' .github/workflows/*.yml .github/workflows/*.yaml

Repository: boundlessfi/bounties

Length of output: 931


Pin GitHub Actions to commit SHAs instead of mutable tags.

.github/workflows/check-schema.yml uses mutable action tags (actions/checkout@v4 at lines 18 and 22, actions/setup-node@v4 at line 35); pin to full 40-hex commit SHAs for reproducible, safer CI.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 17-18: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 18-18: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/check-schema.yml at line 18, The workflow uses mutable
tags "actions/checkout@v4" and "actions/setup-node@v4"; update those uses
entries to the corresponding full 40-character commit SHAs (replace each "`@v4`"
occurrence for checkout and setup-node with the commit SHA from the respective
GitHub Actions repo) so the CI references an exact immutable revision; ensure
you update all occurrences in the file (both checkout usages and the setup-node
usage) and commit the updated workflow.

Copy link
Copy Markdown
Contributor

@Benjtalkshow Benjtalkshow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new commit only touches CI config and doesn't address any of the three blockers from the previous review. The fake useEffect stub at line 317 is still there, the declineReason/declinedReason duplication is still there, and the local reviewApplications mirror state is still there.

The dashboard will still crash at runtime the moment the parent re-renders with new applications because the stub throws Error: Function not implemented. Please fix the three items from the previous review before this can go forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement the Decline applicant flow on the application review dashboard

2 participants