Skip to content

Commit b64b1a3

Browse files
committed
Add op/circleci auth, Node+Yarn via mise, and private registry config
- Authenticate with 1Password (op whoami / op signin) after installation - Install and authenticate CircleCI CLI (circleci setup / CIRCLECI_CLI_TOKEN) - Install Node.js (LTS via mise) and Yarn (via corepack) as baseline tools - Add gh auth scopes (read:packages, write:packages) for GitHub Packages - Configure Bundler (contribsys, GitHub Packages, GitHub git sources) - Configure Yarn (@trusted via GitHub Packages, @FortAwesome via Font Awesome) - Add ci/mock-op shim so op commands succeed in CI without a real session - Add doctor checks for circleci, Node, Yarn, and all registry configs - Update AGENTS.md scope to reflect Node.js, Yarn, circleci, and registries
1 parent a949d8e commit b64b1a3

13 files changed

Lines changed: 386 additions & 14 deletions

.github/workflows/ci.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,24 @@ jobs:
1414
- uses: actions/checkout@v4
1515

1616
- name: Run shellcheck
17-
run: shellcheck -x setup.sh doctor.sh lib/*.sh
17+
run: shellcheck -x setup.sh doctor.sh lib/*.sh ci/mock-op
1818

1919
setup-ubuntu:
2020
name: Setup (Ubuntu)
2121
runs-on: ubuntu-latest
2222
steps:
2323
- uses: actions/checkout@v4
2424

25+
- name: Install op mock for CI
26+
run: |
27+
sudo cp ci/mock-op /usr/local/bin/op
28+
sudo chmod +x /usr/local/bin/op
29+
2530
- name: Run setup.sh
2631
run: bash setup.sh
2732
env:
2833
GH_TOKEN: ${{ secrets.TRUSTED_SHARED_SOURCE_GITHUB_TOKEN }}
34+
CIRCLECI_CLI_TOKEN: ${{ secrets.TRUSTED_SHARED_SOURCE_CIRCLECI_TOKEN }}
2935

3036
- name: Run doctor
3137
run: |
@@ -34,3 +40,4 @@ jobs:
3440
bash doctor.sh
3541
env:
3642
GH_TOKEN: ${{ secrets.TRUSTED_SHARED_SOURCE_GITHUB_TOKEN }}
43+
CIRCLECI_CLI_TOKEN: ${{ secrets.TRUSTED_SHARED_SOURCE_CIRCLECI_TOKEN }}

AGENTS.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,19 @@ When adding a new tool installation, provide install commands for all three plat
5050
This repo installs **tool managers, CLI tools, and infrastructure dependencies**:
5151

5252
- Package managers (Homebrew, apt, pacman)
53-
- git, gh, mise, op
53+
- git, gh, mise, op, circleci
5454
- Ruby (latest stable via mise, as global default for `bin/setup` scripts)
55+
- Node.js (latest LTS via mise, as global default)
56+
- Yarn (via corepack, ships with Node.js)
5557
- Build essentials
5658
- Docker, Docker Compose, Colima (macOS only)
5759
- AWS CLI, AWS VPN Client
60+
- Private registry configuration (Bundler for gems, Yarn for npm scopes)
5861

5962
It does **NOT** install:
6063

61-
- Node.js, Python, or other runtimes (left to project `bin/setup` via mise)
62-
- Project-specific Ruby versions (handled by mise + `.mise.toml`)
64+
- Python or other runtimes (left to project `bin/setup` via mise)
65+
- Project-specific Ruby or Node.js versions (handled by mise + `.mise.toml`)
6366
- Application dependencies (gems, npm packages)
6467
- Databases, Redis, Elasticsearch, etc.
6568
- Editor configurations or dotfiles
@@ -82,7 +85,7 @@ It does **NOT** install:
8285

8386
## Commands
8487

85-
- `shellcheck -x setup.sh doctor.sh lib/*.sh` — Lint bash scripts
88+
- `shellcheck -x setup.sh doctor.sh lib/*.sh ci/mock-op` — Lint bash scripts
8689
- `bash -n setup.sh` — Check for syntax errors without executing
8790
- `bash doctor.sh` — Run post-setup diagnostic checks
8891
- `date +%s` — Generate a migration timestamp

ci/mock-op

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
#
3+
# Mock 1Password CLI for CI environments.
4+
#
5+
# Returns hardcoded dummy values so setup.sh code paths execute without
6+
# a real 1Password desktop app or service account. Placed on PATH before
7+
# the real op binary (or in place of it when op is not installed).
8+
9+
case "$*" in
10+
*whoami*)
11+
echo "ci-mock-user@trusted.dev"
12+
;;
13+
*BUNDLE_ENTERPRISE__CONTRIBSYS__COM*)
14+
echo "ci-mock-contribsys-key"
15+
;;
16+
*"Font Awesome"*)
17+
echo "ci-mock-fa-token"
18+
;;
19+
*--version)
20+
echo "2.99.0-mock"
21+
;;
22+
*signin*)
23+
# No-op: mock is already "signed in"
24+
;;
25+
*)
26+
echo "ci-mock-op: unhandled args: $*" >&2
27+
exit 1
28+
;;
29+
esac

doctor.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ source "$SCRIPT_DIR/lib/mise_doctor.sh"
8484
# shellcheck source=lib/1password_doctor.sh
8585
source "$SCRIPT_DIR/lib/1password_doctor.sh"
8686

87+
# shellcheck source=lib/circleci_doctor.sh
88+
source "$SCRIPT_DIR/lib/circleci_doctor.sh"
89+
8790
# shellcheck source=lib/build_doctor.sh
8891
source "$SCRIPT_DIR/lib/build_doctor.sh"
8992

@@ -93,6 +96,9 @@ source "$SCRIPT_DIR/lib/docker_doctor.sh"
9396
# shellcheck source=lib/aws_doctor.sh
9497
source "$SCRIPT_DIR/lib/aws_doctor.sh"
9598

99+
# shellcheck source=lib/registries_doctor.sh
100+
source "$SCRIPT_DIR/lib/registries_doctor.sh"
101+
96102
# shellcheck source=lib/migrate_doctor.sh
97103
source "$SCRIPT_DIR/lib/migrate_doctor.sh"
98104

lib/1password_setup.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,26 @@ else
4242
;;
4343
esac
4444
fi
45+
46+
# ---------------------------------------------------------------------------
47+
# 1Password Authentication
48+
# ---------------------------------------------------------------------------
49+
50+
fmt_header "1Password Authentication"
51+
52+
if op whoami > /dev/null 2>&1; then
53+
fmt_ok "1Password: already signed in"
54+
else
55+
echo " 1Password CLI needs to be authenticated."
56+
echo " This will open a browser/system auth prompt."
57+
echo ""
58+
eval "$(op signin)"
59+
60+
if ! op whoami > /dev/null 2>&1; then
61+
echo ""
62+
echo "ERROR: 1Password authentication failed or was cancelled."
63+
echo "Setup cannot continue without 1Password access."
64+
exit 1
65+
fi
66+
fmt_ok "1Password: signed in"
67+
fi

lib/circleci_doctor.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash
2+
#
3+
# Doctor check: CircleCI CLI.
4+
# Sourced by doctor.sh — do not execute directly.
5+
# Requires: lib/common.sh, doctor helpers (check_pass, check_fail, check_cmd)
6+
7+
fmt_header "CircleCI CLI"
8+
9+
check_cmd "circleci" "circleci"
10+
11+
if cmd_exists circleci; then
12+
version_output="$(circleci version 2>&1 | head -1)"
13+
check_pass "circleci reports version: $version_output"
14+
15+
if circleci diagnostic 2>&1 | grep -q "OK, got a token"; then
16+
check_pass "circleci is authenticated"
17+
else
18+
check_fail "circleci is not authenticated (run: circleci setup)"
19+
fi
20+
fi

lib/circleci_setup.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/bin/bash
2+
#
3+
# CircleCI CLI setup and authentication.
4+
# Sourced by setup.sh — do not execute directly.
5+
# Requires: lib/common.sh
6+
7+
# ---------------------------------------------------------------------------
8+
# CircleCI CLI
9+
# ---------------------------------------------------------------------------
10+
11+
fmt_header "CircleCI CLI"
12+
13+
if cmd_exists circleci; then
14+
fmt_ok "circleci already installed ($(circleci version 2>/dev/null | head -1))"
15+
else
16+
fmt_install "CircleCI CLI"
17+
case "$OS" in
18+
macos)
19+
brew install circleci
20+
;;
21+
ubuntu|arch)
22+
# Official installer — works on any Linux
23+
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/main/install.sh | sudo bash
24+
;;
25+
esac
26+
fi
27+
28+
# ---------------------------------------------------------------------------
29+
# CircleCI Authentication
30+
# ---------------------------------------------------------------------------
31+
32+
fmt_header "CircleCI Authentication"
33+
34+
if circleci diagnostic 2>&1 | grep -q "OK, got a token"; then
35+
fmt_ok "CircleCI CLI: already authenticated"
36+
else
37+
echo " CircleCI CLI needs to be configured."
38+
echo " You will need a personal API token from:"
39+
echo " https://app.circleci.com/settings/user/tokens"
40+
echo ""
41+
circleci setup
42+
43+
if ! circleci diagnostic 2>&1 | grep -q "OK, got a token"; then
44+
echo ""
45+
echo "ERROR: CircleCI CLI authentication failed or was cancelled."
46+
echo "Setup cannot continue without CircleCI access."
47+
exit 1
48+
fi
49+
fmt_ok "CircleCI CLI: authenticated"
50+
fi

lib/git_setup.sh

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,38 @@ fi
5656

5757
fmt_header "GitHub Authentication"
5858

59+
gh_auth_ok=false
60+
gh_scopes_ok=false
61+
5962
if gh auth status > /dev/null 2>&1; then
60-
fmt_ok "Already authenticated with GitHub"
61-
elif [ "${CI:-}" = "true" ]; then
63+
gh_auth_ok=true
64+
# Check for required scopes (read:packages needed for private registries)
65+
gh_status_output="$(gh auth status 2>&1)"
66+
if echo "$gh_status_output" | grep -qE 'read:packages|write:packages'; then
67+
gh_scopes_ok=true
68+
fi
69+
fi
70+
71+
if $gh_auth_ok && $gh_scopes_ok; then
72+
fmt_ok "Authenticated with GitHub (with required scopes)"
73+
elif $gh_auth_ok; then
74+
echo " GitHub CLI is authenticated but missing required scopes (read:packages, write:packages)."
75+
echo " Re-authenticating with required scopes..."
6276
echo ""
63-
echo "ERROR: Not authenticated with GitHub in CI."
64-
echo "Set GH_TOKEN or GITHUB_TOKEN in your workflow environment."
65-
exit 1
77+
gh auth login --web --git-protocol https --scopes read:packages,write:packages
78+
79+
if ! gh auth status > /dev/null 2>&1; then
80+
echo ""
81+
echo "ERROR: GitHub re-authentication failed or was cancelled."
82+
echo "Setup cannot continue without GitHub access."
83+
exit 1
84+
fi
85+
fmt_ok "Authenticated with GitHub (scopes updated)"
6686
else
6787
echo " GitHub CLI needs to be authenticated."
6888
echo " This will open a browser window for GitHub login."
6989
echo ""
70-
gh auth login --web --git-protocol https
90+
gh auth login --web --git-protocol https --scopes read:packages,write:packages
7191

7292
# Verify authentication succeeded before continuing
7393
if ! gh auth status > /dev/null 2>&1; then

lib/mise_doctor.sh

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22
#
3-
# Doctor check: mise and Ruby.
3+
# Doctor check: mise, Ruby, Node.js, and Yarn.
44
# Sourced by doctor.sh — do not execute directly.
55
# Requires: lib/common.sh, doctor helpers (check_pass, check_fail, check_cmd)
66

@@ -38,3 +38,39 @@ if cmd_exists mise; then
3838
else
3939
check_fail "Cannot check Ruby — mise is not installed"
4040
fi
41+
42+
# ---------------------------------------------------------------------------
43+
# Node.js (via mise)
44+
# ---------------------------------------------------------------------------
45+
46+
fmt_header "Node.js (via mise)"
47+
48+
if cmd_exists mise; then
49+
if mise which node > /dev/null 2>&1; then
50+
check_pass "Node.js is available via mise"
51+
node_version="$(mise exec -- node --version 2>&1)"
52+
if [[ "$node_version" == v* ]]; then
53+
check_pass "Node.js executes and reports version: $node_version"
54+
else
55+
check_fail "Node.js returned unexpected output: $node_version"
56+
fi
57+
else
58+
check_fail "Node.js is not available via mise (expected global default)"
59+
fi
60+
else
61+
check_fail "Cannot check Node.js — mise is not installed"
62+
fi
63+
64+
# ---------------------------------------------------------------------------
65+
# Yarn (via corepack)
66+
# ---------------------------------------------------------------------------
67+
68+
fmt_header "Yarn (via corepack)"
69+
70+
if cmd_exists yarn; then
71+
check_pass "yarn is installed"
72+
yarn_version="$(yarn --version 2>&1)"
73+
check_pass "yarn reports version: $yarn_version"
74+
else
75+
check_fail "yarn is not installed (expected via corepack)"
76+
fi

lib/mise_setup.sh

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22
#
3-
# mise version manager and Ruby setup.
3+
# mise version manager, Ruby, Node.js, and Yarn setup.
44
# Sourced by setup.sh — do not execute directly.
55
# Requires: lib/common.sh
66

@@ -69,5 +69,43 @@ if mise which ruby > /dev/null 2>&1; then
6969
else
7070
fmt_install "Ruby (latest stable via mise)"
7171
mise use --global ruby@latest
72-
fmt_ok "Ruby installed: $(mise exec ruby -- ruby --version)"
72+
fmt_ok "Ruby installed: $(mise exec -- ruby --version)"
73+
fi
74+
75+
# ---------------------------------------------------------------------------
76+
# Node.js (via mise — global default for running bin/setup scripts)
77+
# ---------------------------------------------------------------------------
78+
79+
fmt_header "Node.js (via mise)"
80+
81+
if mise which node > /dev/null 2>&1; then
82+
fmt_ok "Node.js already available via mise"
83+
else
84+
fmt_install "Node.js (latest LTS via mise)"
85+
mise use --global node@lts
86+
fmt_ok "Node.js installed: $(mise exec -- node --version)"
87+
fi
88+
89+
# ---------------------------------------------------------------------------
90+
# Yarn (via corepack — ships with Node.js)
91+
# ---------------------------------------------------------------------------
92+
93+
fmt_header "Yarn (via corepack)"
94+
95+
if cmd_exists yarn; then
96+
fmt_ok "yarn already available ($(yarn --version 2>/dev/null))"
97+
else
98+
fmt_install "Enabling corepack for yarn"
99+
mise exec -- corepack enable
100+
101+
# corepack installs shims to the Node prefix bin directory, which may not
102+
# be on PATH yet. Reshim mise so the yarn shim is available.
103+
mise reshim 2>/dev/null || true
104+
105+
if cmd_exists yarn; then
106+
fmt_ok "yarn enabled via corepack"
107+
else
108+
echo " WARNING: yarn was enabled via corepack but is not yet on PATH."
109+
echo " It will be available after restarting your shell."
110+
fi
73111
fi

0 commit comments

Comments
 (0)