Skip to content
Open
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
18 changes: 9 additions & 9 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Deploy

on:
push:
branches: [ "main" ]
branches: [ "main", "Main" ]
workflow_dispatch:
inputs:
dry_run:
Expand Down Expand Up @@ -35,21 +35,21 @@ jobs:
- name: Sync secrets from 1Password (SA preferred, Connect fallback)
env:
# Option 2: Service Account (preferred)
OP_SERVICE_ACCOUNT_TOKEN: $ secrets.OP_SERVICE_ACCOUNT_TOKEN
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
# Option 1: Connect server (fallback)
OP_CONNECT_HOST: $ secrets.OP_CONNECT_HOST
OP_CONNECT_TOKEN: $ secrets.OP_CONNECT_TOKEN
OP_CONNECT_HOST: ${{ secrets.OP_CONNECT_HOST }}
OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }}
# Map selection (auto: staging branch -> staging map)
SECRETS_MAP: $ github.ref_name == 'staging' && '[secrets.map](http://secrets.map).staging.json' || '[secrets.map](http://secrets.map).json'
SECRETS_MAP: ${{ github.ref_name == 'staging' && 'secrets.map.staging.json' || 'secrets.map.json' }}
# DRY_RUN from workflow input
DRY_RUN: $ github.event.inputs.dry_run
DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run || 'false' }}
Copy link

Copilot AI Sep 15, 2025

Choose a reason for hiding this comment

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

The logical OR operator || in GitHub Actions expressions will always evaluate to 'false' when github.event.inputs.dry_run is falsy, but this doesn't handle the case where the workflow is triggered by push events (where github.event.inputs.dry_run is undefined). Use a ternary operator instead: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run || '' }}

Suggested change
DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run || 'false' }}
DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run || github.event_name != 'workflow_dispatch' && 'false' }}

Copilot uses AI. Check for mistakes.
run: |
sudo apt-get update && sudo apt-get install -y jq
bash scripts/[sync-secrets.sh](http://sync-secrets.sh)
bash scripts/sync-secrets.sh

- name: Deploy (Cloudflare Workers)
if: $ github.event.inputs.dry_run != 'true' && github.event.inputs.dry_run != '1'
if: ${{ !(github.event_name == 'workflow_dispatch' && (github.event.inputs.dry_run == 'true' || github.event.inputs.dry_run == '1')) }}
Copy link

Copilot AI Sep 15, 2025

Choose a reason for hiding this comment

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

The deploy condition logic is complex and duplicates the dry-run check logic. Consider simplifying by using a job-level environment variable or extracting this logic into a reusable expression to improve maintainability.

Suggested change
if: ${{ !(github.event_name == 'workflow_dispatch' && (github.event.inputs.dry_run == 'true' || github.event.inputs.dry_run == '1')) }}
if: ${{ env.DRY_RUN != 'true' && env.DRY_RUN != '1' }}

Copilot uses AI. Check for mistakes.
env:
CLOUDFLARE_API_TOKEN: $ secrets.CLOUDFLARE_API_TOKEN
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
npx wrangler deploy
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ yarn-debug.log*
yarn-error.log*
.pnpm-store
.DS_Store
Notion_API_Documentation_Hub.code-workspace
29 changes: 29 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#2f7c47",
"activityBar.background": "#2f7c47",
"activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799",
"commandCenter.border": "#e7e7e799",
"editorGroup.border": "#2f7c47",
"panel.border": "#2f7c47",
"sash.hoverBorder": "#2f7c47",
"sideBar.border": "#2f7c47",
"statusBar.background": "#215732",
"statusBar.border": "#215732",
"statusBar.debuggingBackground": "#572146",
"statusBar.debuggingBorder": "#572146",
"statusBar.debuggingForeground": "#e7e7e7",
"statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#2f7c47",
"statusBarItem.remoteBackground": "#215732",
"statusBarItem.remoteForeground": "#e7e7e7",
"tab.activeBorder": "#2f7c47",
"titleBar.activeBackground": "#215732",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.border": "#215732",
"titleBar.inactiveBackground": "#21573299",
"titleBar.inactiveForeground": "#e7e7e799"
},
"peacock.color": "#215732"
}
253 changes: 253 additions & 0 deletions Notion Docs/#Neovimdocsquickreference#.md

Large diffs are not rendered by default.

82 changes: 80 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,80 @@
# Notion_API_Documentation_Hub
CF Worker that parses API documention and creates call cards on the API Hub in Notion.
# Notion API Documentation Hub

Cloudflare Worker that parses Notion pages for API documentation and creates structured "call cards" in your Notion API Hub. It streamlines keeping your API catalog up to date by syncing secrets from 1Password and deploying via GitHub Actions.

## One‑click Deploy

Deploy this Worker to your Cloudflare account:

[![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/PCWProps/Notion_API_Documentation_Hub)

## Prerequisites

- Node.js 18+ (Node 20 recommended)
- Cloudflare account and a Workers project
- 1Password account (Service Account recommended) or 1Password Connect

## Install

```bash
npm install
```

This repo pins Wrangler in devDependencies, so the `wrangler` command will resolve locally.

## Configure

1. Copy or prepare your secrets maps in the repo root:
- `secrets.map.json` (default)
- `secrets.map.staging.json` (optional, used automatically on `staging` branch)
Each map should be a JSON object mapping Cloudflare secret names to 1Password item fields, for example:
```json
{
"NOTION_API_KEY": "op://MyVault/Notion API Key/credential",
"CLOUDFLARE_ACCOUNT_ID": "op://MyVault/Cloudflare Account/Account ID"
}
```
2. Create GitHub Actions repo secrets (Settings → Secrets and variables → Actions):
- `OP_SERVICE_ACCOUNT_TOKEN` (preferred) or `OP_CONNECT_HOST` + `OP_CONNECT_TOKEN`
- `CLOUDFLARE_API_TOKEN` (with permissions to manage Workers secrets and deploy)

## Local Development

```bash
npm run dev
```

This runs `wrangler dev` using your local environment. You can set local environment variables or use a `.env` file for development only. The CI sync script does not source `.env`; it only parses simple KEY=VALUE lines to avoid executing non-shell content.

## Deploy

From CI: Push to `main`/`Main` or run the workflow manually. The workflow will:

1. Install dependencies and 1Password CLI
2. Sync secrets from 1Password into Cloudflare Worker secrets
3. Deploy via `npx wrangler deploy`

Manual deploy from your machine (optional):

```bash
npx wrangler deploy
```

## CI Dry Run

Trigger the workflow via "Run workflow" and set `dry_run: true` to verify secret resolution without writing to Cloudflare. You’ll see `[DRY_RUN] would set secret: ...` lines and the deploy step will be skipped.

## Project Structure

- `src/` — Worker source
- `scripts/sync-secrets.sh` — Syncs 1Password secrets to Cloudflare Worker secrets using `secrets.map*.json`
- `.github/workflows/deploy.yml` — CI deploy pipeline

## Troubleshooting

- Syntax error near `(` in CI usually indicates the shell tried to execute non-shell content. The workflow and scripts here avoid that by using quoted heredocs and strict parsing.
- Ensure GitHub secrets are set and that your `secrets.map*.json` paths are valid 1Password references.

## License

See `LICENSE`.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20250224.0",
"wrangler": "^3.0.0",
"typescript": "^5.4.0"
}
}
40 changes: 28 additions & 12 deletions scripts/sync-secrets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ if [[ "${1:-}" == "--from-env" ]]; then
MODE_FROM_ENV=1
fi

MAP_FILE="${SECRETS_MAP:-[secrets.map](http://secrets.map).json}"
if [[ "${GITHUB_REF_NAME:-}" == "staging" && -z "${SECRETS_MAP:-}" && -f "[secrets.map](http://secrets.map).staging.json" ]]; then
MAP_FILE="[secrets.map](http://secrets.map).staging.json"
MAP_FILE="${SECRETS_MAP:-secrets.map.json}"
if [[ "${GITHUB_REF_NAME:-}" == "staging" && -z "${SECRETS_MAP:-}" && -f "secrets.map.staging.json" ]]; then
MAP_FILE="secrets.map.staging.json"
fi

ensure_tools() {
Expand All @@ -35,7 +35,9 @@ ensure_tools() {

put_secret() {
local key="$1" val="$2"
if [[ -n "${DRY_RUN:-}" && "$DRY_RUN" != "0" ]]; then
local dr="${DRY_RUN:-}"
dr="${dr,,}"
if [[ "$dr" == "1" || "$dr" == "true" ]]; then
echo "[DRY_RUN] would set secret: $key"
else
printf "%s" "$val" | wrangler secret put "$key" --quiet
Expand All @@ -48,14 +50,28 @@ sync_from_env() {
if [[ ! -f .env ]]; then
echo ".env not found" >&2; exit 1
fi
# shellcheck disable=SC2046
set -a; source .env; set +a
while IFS='=' read -r k v; do
[[ -z "$k" || "$k" =~ ^# ]] && continue
k_trim="${k%% *}"; v_trim="${!k_trim:-}"
[[ -z "$v_trim" ]] && continue
put_secret "$k_trim" "$v_trim"
done < <(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' .env || true)
# Parse simple KEY=VALUE lines without sourcing to avoid executing arbitrary content
while IFS= read -r line; do
# trim leading/trailing whitespace
trimmed="${line#${line%%[![:space:]]*}}" # remove leading
trimmed="${trimmed%${trimmed##*[![:space:]]}}" # remove trailing
Comment on lines +56 to +57
Copy link

Copilot AI Sep 15, 2025

Choose a reason for hiding this comment

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

The whitespace trimming logic uses complex parameter expansion that is hard to read and maintain. Consider using a simpler approach like trimmed=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') or the built-in read command with IFS manipulation for better readability.

Suggested change
trimmed="${line#${line%%[![:space:]]*}}" # remove leading
trimmed="${trimmed%${trimmed##*[![:space:]]}}" # remove trailing
trimmed=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

Copilot uses AI. Check for mistakes.
# skip blanks and comments
[[ -z "$trimmed" || "$trimmed" =~ ^[[:space:]]*# ]] && continue
# drop optional 'export '
line_no_export="${trimmed#export }"
# require KEY=VALUE
if [[ "$line_no_export" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
key="${BASH_REMATCH[1]}"
val="${BASH_REMATCH[2]}"
# strip surrounding quotes if present
if [[ "$val" =~ ^\"(.*)\"$ ]]; then val="${BASH_REMATCH[1]}"; fi
if [[ "$val" =~ ^\'(.*)\'$ ]]; then val="${BASH_REMATCH[1]}"; fi
# unescape common sequences
val="${val//\\n/$'\n'}"
val="${val//\\t/$'\t'}"
put_secret "$key" "$val"
fi
done < .env
}

sync_from_1password() {
Expand Down