Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions contrib/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# contrib

Staging area for connector source that is destined for its own repository but has nowhere to live
yet.

Nothing here is part of the `github.com/conductorone/baton-sdk` Go module. Each subdirectory is a
self-contained module with its own `go.mod`, so the SDK's `go build ./...`, `go test ./...` and
`golangci-lint run` do not descend into it, and the SDK's own dependency graph is unaffected.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: the isolation cuts both ways — because contrib/baton-appstoreconnect/.github/workflows/ is nested rather than at the repo root, none of those workflows run here, and the root .github/workflows/ never descends into contrib/. So while this code lives in baton-sdk nothing builds, tests, or lints it in CI, and go.mod pins the published baton-sdk v0.26.0 rather than replace-ing the local tree, so it is not verified against this repo's SDK either. Worth either a small root job that runs go build ./... && go test ./... per contrib/*/go.mod, or a line here stating plainly that the staged copy is CI-unverified.


## `baton-appstoreconnect`

A complete Apple App Store Connect connector (CXH-2377). It belongs in
`ConductorOne/baton-appstoreconnect`, created from
[baton-starter-pack](https://github.com/ConductorOne/baton-starter-pack) like every other connector.

To extract it into that repository once it exists:

```bash
git subtree split --prefix=contrib/baton-appstoreconnect -b appstoreconnect-export
git push git@github.com:ConductorOne/baton-appstoreconnect.git appstoreconnect-export:main
```

Then, in the new repository, run `make update-deps` to vendor dependencies (connector repos vendor;
this staged copy does not, to keep the diff reviewable) and let the `generate-baton-metadata`
workflow produce `baton_capabilities.json` and `config_schema.json`.

Once the connector lives in its own repository, delete this directory.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# This file is managed by baton-admin. DO NOT EDIT!!!
name: Check versions
on:
pull_request:
branches:
- main

jobs:
block-versions-yaml-edits:
runs-on: ubuntu-latest
steps:
- name: Check for .versions.yaml changes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
changed_files=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files --paginate --jq '.[].filename')
if echo "$changed_files" | grep -qx '.versions.yaml'; then
echo "::error::.versions.yaml is managed by baton-admin and must not be edited in PRs. Update versions from baton-admin first."
exit 1
fi
echo ".versions.yaml not modified — OK"

verify-versions-match:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Verify go.mod matches .versions.yaml
run: |
# Get .versions.yaml from base branch
base_ref="${{ github.event.pull_request.base.ref }}"
if ! git show "origin/${base_ref}:.versions.yaml" > /tmp/base-versions.yaml 2>/dev/null; then
echo "No .versions.yaml found on ${base_ref} — skipping check"
exit 0
fi

mismatch=0

version_lt() {
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -1)" = "$1" ] && [ "$1" != "$2" ]
}

# Compare go-version. .versions.yaml is the managed minimum; go.mod
# may be higher when a connector's dependency graph requires it.
expected_go=$(yq -r '.go-version' /tmp/base-versions.yaml)
actual_go=$(awk '/^go [0-9]/{print $2}' go.mod)
if version_lt "$actual_go" "$expected_go"; then
echo "::error::Go version too low: .versions.yaml requires at least ${expected_go}, but go.mod has ${actual_go}. Update versions from baton-admin first."
mismatch=1
elif version_lt "$expected_go" "$actual_go"; then
echo "::warning::go.mod uses ${actual_go}, which is newer than .versions.yaml minimum ${expected_go}. baton-admin will sync the higher Go pin."
else
echo "Go version matches: ${expected_go}"
fi

# Compare baton-sdk version
expected_sdk=$(yq -r '.dependencies.baton-sdk // ""' /tmp/base-versions.yaml)
if [ -n "$expected_sdk" ]; then
actual_sdk=$(grep 'github.com/conductorone/baton-sdk' go.mod | grep -v '// indirect' | awk '{print $2}' | head -1)
if [ "$expected_sdk" != "$actual_sdk" ]; then
echo "::error::baton-sdk version mismatch: .versions.yaml expects ${expected_sdk}, but go.mod has ${actual_sdk}. Update versions from baton-admin first."
mismatch=1
else
echo "baton-sdk version matches: ${expected_sdk}"
fi
fi

# Compare baton-http version (warning only — not all repos use it)
expected_http=$(yq -r '.dependencies.baton-http // ""' /tmp/base-versions.yaml)
if [ -n "$expected_http" ]; then
actual_http=$(grep 'github.com/conductorone/baton-http' go.mod | grep -v '// indirect' | awk '{print $2}' | head -1)
if [ -z "$actual_http" ]; then
echo "::warning::baton-http is listed in .versions.yaml (${expected_http}) but not found in go.mod"
elif [ "$expected_http" != "$actual_http" ]; then
echo "::error::baton-http version mismatch: .versions.yaml expects ${expected_http}, but go.mod has ${actual_http}. Update versions from baton-admin first."
mismatch=1
else
echo "baton-http version matches: ${expected_http}"
fi
fi

if [ "$mismatch" -ne 0 ]; then
echo "::error::Version mismatches detected. Dependency versions in go.mod must match .versions.yaml on main. Update versions from baton-admin first."
exit 1
fi
echo "All versions match — OK"
71 changes: 71 additions & 0 deletions contrib/baton-appstoreconnect/.github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: ci
on:
pull_request:
types: [opened, reopened, synchronize]
push:
branches:
- main
jobs:
go-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Run linters
uses: golangci/golangci-lint-action@v9
with:
skip-cache: true
version: v2.9.0
args: --timeout=3m
go-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Build baton-appstoreconnect
run: go build ./cmd/baton-appstoreconnect
- name: go tests
run: go test -v ./...
# Live-tenant provisioning checks. These need an App Store Connect API key with the Admin role
# stored in repository secrets, plus the ids of a role/app entitlement and a principal to move.
# They are skipped until those secrets exist.
connector-tests:
runs-on: ubuntu-latest
if: ${{ vars.CI_ROLE_ENTITLEMENT != '' }}
env:
BATON_LOG_LEVEL: debug
BATON_KEY_ID: ${{ secrets.KEY_ID }}
BATON_ISSUER_ID: ${{ secrets.ISSUER_ID }}
BATON_PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Build baton-appstoreconnect
run: go build ./cmd/baton-appstoreconnect
- name: Grant/Revoke Role
uses: ConductorOne/github-workflows/actions/sync-test@v4
with:
connector: ./baton-appstoreconnect
baton-entitlement: ${{ vars.CI_ROLE_ENTITLEMENT }}
baton-principal: ${{ vars.CI_ROLE_PRINCIPAL }}
baton-principal-type: user
- name: Grant/Revoke App Access
if: ${{ vars.CI_APP_ENTITLEMENT != '' }}
uses: ConductorOne/github-workflows/actions/sync-test@v4
with:
connector: ./baton-appstoreconnect
baton-entitlement: ${{ vars.CI_APP_ENTITLEMENT }}
baton-principal: ${{ vars.CI_APP_PRINCIPAL }}
baton-principal-type: user
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# This file is managed by baton-admin. DO NOT EDIT!!!
name: Connector Docs

on:
pull_request:
types: [opened, reopened, synchronize]
push:
branches:
- main

permissions:
contents: read
pull-requests: read

jobs:
connector-docs:
uses: ConductorOne/github-workflows/.github/workflows/connector-docs-verify.yaml@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# This file is managed by baton-admin. DO NOT EDIT!!!
name: Generate Baton Metadata

on:
push:
branches:
- main
pull_request:
types: [opened, reopened, synchronize]

jobs:
generate_outputs:
if: github.event_name == 'push' && github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest

steps:
- name: Mint baton-ci app token
id: ci-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.BATON_CI_CLIENT_ID }}
private-key: ${{ secrets.BATON_CI_SECRET_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}

- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ steps.ci-token.outputs.token }}
fetch-depth: 0

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"

- name: Build
run: go build -o connector ./cmd/baton-appstoreconnect

- name: Run and save config output
run: ./connector config > config_schema.json

- name: Run and save capabilities output
run: ./connector capabilities > baton_capabilities.json

- name: Commit changes
uses: EndBug/add-and-commit@v9
with:
default_author: github_actions
message: "Updating baton config schema and capabilities."
add: |
config_schema.json
baton_capabilities.json

validate_metadata:
if: github.event_name == 'pull_request' && github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"

- name: Build
run: go build -o connector ./cmd/baton-appstoreconnect

- name: Run and save config output
run: ./connector config > config_schema.json

- name: Run and save capabilities output
run: ./connector capabilities > baton_capabilities.json

# Check 1: verify committed JSON matches binary output
- name: Verify committed metadata is up to date
id: metadata-check
continue-on-error: true
run: |
CAPS_STALE=false
CONFIG_STALE=false

# Semantic JSON comparison (tolerant of whitespace/formatting differences)
COMMITTED_CAPS=$(git show HEAD:baton_capabilities.json 2>/dev/null | jq -cS . 2>/dev/null || echo "")
GENERATED_CAPS=$(jq -cS . baton_capabilities.json 2>/dev/null || echo "")
if [ "$COMMITTED_CAPS" != "$GENERATED_CAPS" ]; then
CAPS_STALE=true
echo "::warning::baton_capabilities.json differs from binary output"
git diff -- baton_capabilities.json
fi

COMMITTED_CONFIG=$(git show HEAD:config_schema.json 2>/dev/null | jq -cS . 2>/dev/null || echo "")
GENERATED_CONFIG=$(jq -cS . config_schema.json 2>/dev/null || echo "")
if [ "$COMMITTED_CONFIG" != "$GENERATED_CONFIG" ]; then
CONFIG_STALE=true
echo "::warning::config_schema.json differs from binary output"
git diff -- config_schema.json
fi

if [ "$CAPS_STALE" = "true" ] || [ "$CONFIG_STALE" = "true" ]; then
echo ""
echo "::error::The committed baton_capabilities.json and/or config_schema.json are out of date."
echo "::error::The connector binary generates different metadata than what's committed."
echo "::error::Run './connector capabilities > baton_capabilities.json' and './connector config > config_schema.json' locally, then commit the updated files."
echo "::error::Or use the fix-ci-checks skill to update automatically."
echo ""
echo "Capabilities stale: $CAPS_STALE"
echo "Config stale: $CONFIG_STALE"
exit 1
fi

echo "Committed metadata matches binary output."

# Check 2: verify docs reflect current metadata
- name: Verify docs match current metadata
id: docs-check
if: always()
continue-on-error: true
run: |
CAPS_CHANGED=false
CONFIG_CHANGED=false

BASE_SHA=$(git merge-base HEAD origin/main 2>/dev/null || echo "")

# Compare PR's committed metadata with main using semantic JSON comparison
# (jq -cS normalizes formatting so whitespace-only changes don't trigger docs requirement)
if [ -n "$BASE_SHA" ]; then
BASE_CAPS=$(git show "$BASE_SHA:baton_capabilities.json" 2>/dev/null | jq -cS . 2>/dev/null || echo "")
HEAD_CAPS=$(jq -cS . baton_capabilities.json 2>/dev/null || echo "")
if [ "$BASE_CAPS" != "$HEAD_CAPS" ]; then
CAPS_CHANGED=true
fi

BASE_CONFIG=$(git show "$BASE_SHA:config_schema.json" 2>/dev/null | jq -cS . 2>/dev/null || echo "")
HEAD_CONFIG=$(jq -cS . config_schema.json 2>/dev/null || echo "")
if [ "$BASE_CONFIG" != "$HEAD_CONFIG" ]; then
CONFIG_CHANGED=true
fi
fi

if [ "$CAPS_CHANGED" = "false" ] && [ "$CONFIG_CHANGED" = "false" ]; then
echo "Metadata unchanged — no doc update needed."
exit 0
fi

# Check if docs/connector.mdx was updated in this PR
DOCS_CHANGED=false
if [ -n "$BASE_SHA" ]; then
if git diff --name-only "$BASE_SHA" HEAD | grep -q "docs/connector.mdx"; then
DOCS_CHANGED=true
fi
fi

if [ "$DOCS_CHANGED" = "true" ]; then
echo "Metadata changed and docs were updated — check passed."
exit 0
fi

echo "::error::Connector capabilities or config schema changed but docs/connector.mdx was not updated."
echo "::error::Run the fix-ci-checks skill locally to update docs from the current metadata."
echo "Capabilities changed: $CAPS_CHANGED"
echo "Config changed: $CONFIG_CHANGED"
exit 1

# Fail the job if either PR check failed
- name: Enforce PR check results
if: always()
run: |
FAILURES=""
if [ "${{ steps.metadata-check.outcome }}" = "failure" ]; then
FAILURES="${FAILURES}\n- Committed metadata is out of date"
fi
if [ "${{ steps.docs-check.outcome }}" = "failure" ]; then
FAILURES="${FAILURES}\n- Docs not updated to match metadata changes"
fi
if [ -n "$FAILURES" ]; then
echo "PR checks failed:"
echo -e "$FAILURES"
echo ""
echo "Run the fix-ci-checks skill to resolve these issues."
exit 1
fi
Loading
Loading