From ff10b1d467b3b53ef8eef99ef231a56147b15df2 Mon Sep 17 00:00:00 2001 From: Humera-Yameen Date: Wed, 30 Sep 2026 01:23:01 +1000 Subject: [PATCH 1/5] feat!: v2 uses apisec-code-bolt Surface CLI Replace code-discovery with analyze, legacy profile, skip-if-no-routes, and APISEC_REGISTRATION_CODE. Breaking: no spec PR; deprecated outputs empty. --- README.md | 189 +++++++++--------------------------------------- action.yml | 208 +++++++++++++++++++++++------------------------------ 2 files changed, 120 insertions(+), 277 deletions(-) diff --git a/README.md b/README.md index fc2c8aa..2baa701 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,11 @@ # Code Discovery GitHub Action -Automatically discover API endpoints in your repository and upload them to the APIsec platform. This action uses the Code Discovery CLI to scan your codebase, generate OpenAPI specifications, and create pull requests with the results. +Scans your repository with the Surface CLI (`apisec-code-bolt`) and uploads the result to APIsec. Existing Code Discovery apps are updated in place. -## Features - -- 🔍 **Automatic Framework Detection** - Detects Spring Boot, Micronaut, Argos, FastAPI, Flask, Django, Express, ASP.NET Core, Gin and more -- 📝 **OpenAPI Generation** - Generates OpenAPI 3.0 specifications from your code -- 🔄 **State Management** - Tracks application and instance IDs across runs -- 🔀 **Pull Request Creation** - Automatically creates PRs with discovered endpoints -- ⚠️ **Non-Blocking** - Warnings don't fail your workflow +Ship this cutover as **`v1.0.0`** / **`v1`**. Keep **`v0.1.8`** pinned if you need to roll back to Code Discovery. ## Usage -### Basic Example - ```yaml name: API Discovery @@ -24,183 +16,66 @@ on: jobs: discover: runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write steps: - uses: actions/checkout@v4 - - uses: apisec-inc/apisec-bolt-code-discovery-github-action@v0.1.7 + - uses: apisec-inc/apisec-bolt-code-discovery-github-action@v1 with: api-endpoint: ${{ secrets.API_DISCOVERY_ENDPOINT }} api-token: ${{ secrets.API_DISCOVERY_TOKEN }} ``` -### Scheduled Runs +`api-endpoint` is the applicationsservice base URL (the same value Surface uses as `--api-url`). -```yaml -name: API Discovery - -on: - schedule: - - cron: '0 2 * * *' # Daily at 2 AM - -jobs: - discover: - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - uses: actions/checkout@v4 - - uses: apisec-inc/apisec-bolt-code-discovery-github-action@v0.1.7 - with: - api-endpoint: ${{ secrets.API_DISCOVERY_ENDPOINT }} - api-token: ${{ secrets.API_DISCOVERY_TOKEN }} - pr-title: 'chore: update OpenAPI specification [skip ci]' - pr-body: 'Automatically generated OpenAPI specification from code discovery' -``` - -### Custom Configuration - -```yaml -- uses: apisec-inc/apisec-bolt-code-discovery-github-action@v0.1.7 - with: - api-endpoint: ${{ secrets.API_DISCOVERY_ENDPOINT }} - api-token: ${{ secrets.API_DISCOVERY_TOKEN }} - repo-path: './backend' - config-path: './backend/.codediscovery.yml' -``` - -### Dry Run (Testing) +### Dry run ```yaml -- uses: apisec-inc/apisec-bolt-code-discovery-github-action@v0.1.7 +- uses: apisec-inc/apisec-bolt-code-discovery-github-action@v1 with: api-endpoint: ${{ secrets.API_DISCOVERY_ENDPOINT }} api-token: ${{ secrets.API_DISCOVERY_TOKEN }} - dry-run: true # Skip API upload, still generates spec + dry-run: true ``` ## Inputs | Input | Required | Default | Description | |-------|----------|---------|-------------| -| `api-endpoint` | ✅ Yes | - | External API endpoint URL | -| `api-token` | ✅ Yes | - | Bearer token for API authentication | -| `repo-path` | ❌ No | `.` | Path to repository root to analyze | -| `config-path` | ❌ No | `.codediscovery.yml` | Path to .codediscovery.yml config file | -| `pr-title` | ❌ No | `chore: update OpenAPI specification` | Pull request title | -| `pr-body` | ❌ No | `Automatically generated OpenAPI specification` | Pull request body | -| `dry-run` | ❌ No | `false` | Skip API upload (for testing) | -| `host-url` | ⚠️ Recommended | `''` | OpenAPI server URL (e.g. `https://api.example.com`). Required when no parser can extract a host from your sources; without it, state isn't saved across runs. | +| `api-endpoint` | Yes | | APIsec applicationsservice base URL | +| `api-token` | Yes | | APIsec personal access token | +| `repo-path` | No | `.` | Repository root to analyze | +| `dry-run` | No | `false` | Analyse only; do not upload | +| `config-path` | No | `.codediscovery.yml` | Ignored | +| `host-url` | No | | Ignored — set the instance host in the APIsec console | +| `pr-title` | No | | Ignored — no spec PR is opened | +| `pr-body` | No | | Ignored — no spec PR is opened | ## Outputs | Output | Description | |--------|-------------| -| `spec-path` | Path to generated OpenAPI specification (`apisec-bolt-code-discovery/openapi_spec.yaml`) | -| `application-id` | Application ID from API (if uploaded) | -| `instance-id` | Instance ID from API (if uploaded) | -| `pr-url` | URL of created pull request | -| `success` | Whether discovery succeeded | - -## Required Permissions +| `success` | `true` only when the CLI exited 0 | +| `application-id` | APIsec application id after a successful upload | +| `endpoints-count` | Number of API routes found | +| `frameworks-detected` | Comma-separated frameworks | +| `spec-path` | Empty (spec is published by the engine) | +| `instance-id` | Empty | +| `pr-url` | Empty | -This action requires the following GitHub permissions: +The Action never fails the workflow. Check `success` if a later step should stop. -- `contents: write` - To commit generated files -- `pull-requests: write` - To create pull requests +## How it works -Add these permissions to your workflow: +1. Installs Python 3.11 and Surface CLI `0.1.11` +2. Registers or reuses one APIsec application per GitHub repo (`github:`) +3. Uploads the Surface manifest; the reasoning engine publishes the OpenAPI spec -```yaml -permissions: - contents: write - pull-requests: write -``` - -## How It Works - -1. **Install CLI** - Installs Code Discovery CLI (version 0.7.2) -2. **Configure Credentials** - Sets up API credentials from inputs -3. **Run Discovery** - Scans repository and generates OpenAPI spec -4. **Create PR** - Creates a new branch, commits files, and opens a pull request - -### Generated Files - -The action generates files in the `apisec-bolt-code-discovery/` directory: - -- `openapi_spec.yaml` - OpenAPI 3.0 specification -- `state.yaml` - State file tracking application and instance IDs - -Both files are automatically committed to the pull request. - -## State Management - -The action uses state management to track your application across runs: - -- **First Run**: Creates a new application and stores IDs in `state.yaml` -- **Subsequent Runs**: Updates the existing application using stored IDs - -The state file (`apisec-bolt-code-discovery/state.yaml`) is safe to commit and contains no sensitive data. - -## Error Handling - -The action is designed to be non-blocking: - -- ⚠️ Discovery warnings don't fail the workflow -- ⚠️ API errors are logged but don't stop execution -- ✅ Workflow continues even if discovery encounters issues - -## Supported Frameworks - -- **Java**: Spring Boot, Micronaut, Argos -- **Python**: FastAPI, Flask, Django -- **Node.js**: Express -- **.NET**: ASP.NET Core -- **Go**: Gin - -More frameworks coming soon! +Set the instance host URL in the APIsec console after the first run if the default `/` is not your API base. ## Requirements -- Python 3.9+ (available on GitHub Actions runners) -- Git (for PR creation) -- GitHub CLI (`gh`) - pre-installed on GitHub Actions runners - -## License - -MIT License - see [LICENSE](LICENSE) file for details. - -## Support - -For issues and questions, please open an issue in the [repository](https://github.com/apisec-inc/apisec-bolt-code-discovery-github-action). - -## Quick Start - -1. **Add workflow file** `.github/workflows/api-discovery.yml`: - ```yaml - name: API Discovery - on: - push: - branches: [main] - jobs: - discover: - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - uses: actions/checkout@v4 - - uses: apisec-inc/apisec-bolt-code-discovery-github-action@v0.1.7 - with: - api-endpoint: ${{ secrets.API_DISCOVERY_ENDPOINT }} - api-token: ${{ secrets.API_DISCOVERY_TOKEN }} - ``` - -2. **Configure secrets** in repository Settings → Secrets: - - `API_DISCOVERY_ENDPOINT` - Your API endpoint URL - - `API_DISCOVERY_TOKEN` - Your Bearer token +- Python 3.11 (installed by the Action) +- An APIsec PAT with `app:create` -3. **Push to trigger** - The action will run automatically! +## Rollback +Pin `@v0.1.8` to run Code Discovery again. diff --git a/action.yml b/action.yml index 658bce4..32d6834 100644 --- a/action.yml +++ b/action.yml @@ -1,5 +1,5 @@ name: 'Code Discovery - API Discovery' -description: 'Automatically discover API endpoints and upload to API security platform' +description: 'Discover API endpoints with Surface CLI and upload them to APIsec' author: 'APIsec Bolt' branding: @@ -8,170 +8,138 @@ branding: inputs: api-endpoint: - description: 'External API endpoint URL' + description: 'APIsec applicationsservice base URL (same as Surface --api-url)' required: true api-token: - description: 'Bearer token for API authentication' + description: 'APIsec personal access token' required: true repo-path: description: 'Path to repository root to analyze' required: false default: '.' config-path: - description: 'Path to .codediscovery.yml config file (optional)' + description: 'Ignored. Surface does not use .codediscovery.yml. Kept so existing workflows do not break.' required: false default: '.codediscovery.yml' pr-title: - description: 'Pull request title' + description: 'Ignored. The Action no longer opens a spec PR.' required: false default: 'chore: update OpenAPI specification' pr-body: - description: 'Pull request body' + description: 'Ignored. The Action no longer opens a spec PR.' required: false default: 'Automatically generated OpenAPI specification' dry-run: - description: 'Skip API upload (for testing)' + description: 'Analyse only; do not register or upload' required: false default: 'false' host-url: - description: >- - Explicit OpenAPI server URL for the discovered API - (e.g. https://api.example.com). Required when no parser extracts - a host from your sources; without it the APIsec backend cannot - create an application instance and state is never saved across runs. + description: 'Ignored. Set the instance host in the APIsec console after the app is created.' required: false default: '' outputs: spec-path: - description: 'Path to generated OpenAPI specification' + description: 'Empty. The spec is published by the reasoning engine, not written to the repo.' + value: ${{ steps.discovery.outputs.spec-path }} endpoints-count: - description: 'Number of endpoints discovered' + description: 'Number of API routes found' + value: ${{ steps.discovery.outputs.endpoints-count }} frameworks-detected: description: 'Comma-separated list of detected frameworks' + value: ${{ steps.discovery.outputs.frameworks-detected }} application-id: - description: 'Application ID from API (if uploaded)' + description: 'APIsec application id (if uploaded)' + value: ${{ steps.discovery.outputs.application-id }} instance-id: - description: 'Instance ID from API (if uploaded)' + description: 'Empty. Surface does not return an instance id.' + value: ${{ steps.discovery.outputs.instance-id }} pr-url: - description: 'URL of created pull request' + description: 'Empty. The Action no longer opens a spec PR.' + value: ${{ steps.discovery.outputs.pr-url }} success: - description: 'Whether discovery succeeded' + description: 'true only when the CLI exited 0' + value: ${{ steps.discovery.outputs.success }} runs: using: 'composite' steps: - - name: Install Code Discovery CLI - shell: bash - run: | - python3 -m pip install --upgrade pip - pip install code-discovery==0.7.2 - - - name: Configure API credentials + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Surface CLI shell: bash run: | - mkdir -p ~/.config - cat > ~/.apisec << EOF - [api-discovery] - endpoint = ${{ inputs.api-endpoint }} - token = ${{ inputs.api-token }} - EOF - chmod 600 ~/.apisec - - - name: Run API Discovery + python -m pip install --upgrade pip + pip install "apisec-code-bolt==0.1.11" + apisec-code-bolt telemetry off || true + + - name: Run Surface discovery id: discovery shell: bash continue-on-error: true + env: + API_ENDPOINT: ${{ inputs.api-endpoint }} + API_TOKEN: ${{ inputs.api-token }} + REPO_PATH: ${{ inputs.repo-path }} + DRY_RUN: ${{ inputs.dry-run }} + CONFIG_PATH: ${{ inputs.config-path }} + HOST_URL: ${{ inputs.host-url }} + APISEC_CANONICAL_REPO_ID: github:${{ github.repository_id }} + APISEC_RUN_PROFILE: legacy + APISEC_REGISTRATION_CODE: ci-github-action + APISEC_PAT: ${{ inputs.api-token }} run: | - # Build command arguments - CMD_ARGS="--repo-path ${{ inputs.repo-path }}" - CMD_ARGS="$CMD_ARGS --output apisec-bolt-code-discovery/openapi_spec.yaml" - - if [ "${{ inputs.config-path }}" != ".codediscovery.yml" ]; then - CMD_ARGS="$CMD_ARGS --config ${{ inputs.config-path }}" + if [ "$CONFIG_PATH" != ".codediscovery.yml" ]; then + echo "::warning::config-path is ignored; Surface does not use .codediscovery.yml" fi - - if [ "${{ inputs.dry-run }}" == "true" ]; then - CMD_ARGS="$CMD_ARGS --dry-run" + if [ -n "$HOST_URL" ]; then + echo "::warning::host-url is ignored; set the instance host in the APIsec console after the app is created" fi - if [ -n "${{ inputs.host-url }}" ]; then - CMD_ARGS="$CMD_ARGS --server ${{ inputs.host-url }}" + ARGS=(--log-format json analyze "$REPO_PATH" --no-detect-monorepo --skip-if-no-routes --api-url "$API_ENDPOINT") + if [ "$DRY_RUN" = "true" ]; then + ARGS+=(--dry-run) fi + set +e + apisec-code-bolt "${ARGS[@]}" 2> >(tee scan.ndjson >&2) + RC=$? + set -e - # Run discovery (continue on error - don't fail workflow) - code-discovery $CMD_ARGS || echo "⚠️ Discovery completed with warnings" - - # Extract outputs from state file and CLI output - if [ -f apisec-bolt-code-discovery/state.yaml ]; then - APP_ID=$(grep 'applicationId:' apisec-bolt-code-discovery/state.yaml | cut -d'"' -f2 || echo "") - INSTANCE_ID=$(grep 'instanceId:' apisec-bolt-code-discovery/state.yaml | cut -d'"' -f2 || echo "") - echo "application-id=$APP_ID" >> $GITHUB_OUTPUT - echo "instance-id=$INSTANCE_ID" >> $GITHUB_OUTPUT - fi - - echo "spec-path=apisec-bolt-code-discovery/openapi_spec.yaml" >> $GITHUB_OUTPUT - echo "success=true" >> $GITHUB_OUTPUT - - - name: Create Pull Request - if: steps.discovery.outcome == 'success' && inputs.dry-run != 'true' - shell: bash - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - # Configure git - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Get base branch (default to main if not available) - BASE_BRANCH="${{ github.ref_name }}" - if [ "$BASE_BRANCH" == "HEAD" ] || [ -z "$BASE_BRANCH" ]; then - BASE_BRANCH="main" - fi - - # Fetch all branches - git fetch origin - - # Create new branch with timestamp - BRANCH_NAME="code-discovery/update-openapi-$(date +%s)" - - # Checkout base branch first, then create new branch - git checkout $BASE_BRANCH 2>/dev/null || git checkout -b $BASE_BRANCH origin/$BASE_BRANCH - git checkout -b $BRANCH_NAME 2>/dev/null || git checkout $BRANCH_NAME - - # Add generated files - git add apisec-bolt-code-discovery/openapi_spec.yaml apisec-bolt-code-discovery/state.yaml 2>/dev/null || true - - # Check if there are changes - if git diff --staged --quiet; then - echo "No changes to commit" - echo "pr-url=" >> $GITHUB_OUTPUT - else - # Commit - git commit -m "${{ inputs.pr-title }}" || exit 0 - - # Push branch - git push origin $BRANCH_NAME --force-with-lease 2>/dev/null || git push origin $BRANCH_NAME - - # Create PR (check if PR already exists first) - EXISTING_PR=$(gh pr list --head $BRANCH_NAME --json number --jq '.[0].number' 2>/dev/null || echo "") - - if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ] && [ "$EXISTING_PR" != "" ]; then - PR_URL=$(gh pr view $EXISTING_PR --json url --jq '.url' 2>/dev/null || echo "") - echo "Using existing pull request: $PR_URL" - else - PR_URL=$(gh pr create \ - --title "${{ inputs.pr-title }}" \ - --body "${{ inputs.pr-body }}" \ - --base $BASE_BRANCH \ - --head $BRANCH_NAME \ - --repo ${{ github.repository }} 2>/dev/null || echo "") - fi - - echo "pr-url=$PR_URL" >> $GITHUB_OUTPUT - - if [ -n "$PR_URL" ]; then - echo "✓ Created pull request: $PR_URL" - fi - fi + RC="$RC" python - <<'PY' + import json + import os + from pathlib import Path + + routes = "" + frameworks = "" + ndjson = Path("scan.ndjson") + if ndjson.exists(): + for line in ndjson.read_text(encoding="utf-8", errors="replace").splitlines(): + try: + obj = json.loads(line) + except json.JSONDecodeError: + continue + if obj.get("event") == "scan_complete": + routes = str(obj.get("routes_found", "")) + frameworks = ",".join(obj.get("frameworks") or []) + + state = Path(os.environ["REPO_PATH"]) / "apisec-code-bolt" / "state.yaml" + app_id = "" + if state.exists(): + for line in state.read_text(encoding="utf-8", errors="replace").splitlines(): + if line.startswith("applicationId:"): + app_id = line.split(":", 1)[1].strip().strip("\"'") + break + out = os.environ["GITHUB_OUTPUT"] + with open(out, "a", encoding="utf-8") as fh: + fh.write(f"endpoints-count={routes}\n") + fh.write(f"frameworks-detected={frameworks}\n") + fh.write(f"application-id={app_id}\n") + fh.write("spec-path=\ninstance-id=\npr-url=\n") + fh.write(f"success={'true' if os.environ['RC'] == '0' else 'false'}\n") + PY + exit 0 From 1226a96a18772c34a2ee564a67ae3f4436ee219a Mon Sep 17 00:00:00 2001 From: Humera-Yameen Date: Wed, 30 Sep 2026 06:38:26 +1000 Subject: [PATCH 2/5] fix: pin apisec-code-bolt to 0.1.10 for PyPI and CI 0.1.11 is not published yet. Bump to the release that includes legacy profile after SurfaceCore merge. --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 32d6834..890d99a 100644 --- a/action.yml +++ b/action.yml @@ -73,7 +73,7 @@ runs: shell: bash run: | python -m pip install --upgrade pip - pip install "apisec-code-bolt==0.1.11" + pip install "apisec-code-bolt==0.1.10" apisec-code-bolt telemetry off || true - name: Run Surface discovery From debe636ef29eddcb9feee5ba164b55659cfa64aa Mon Sep 17 00:00:00 2001 From: Humera-Yameen Date: Wed, 7 Oct 2026 19:14:57 +1100 Subject: [PATCH 3/5] chore: switch to apisec-surface 0.1.13 Co-authored-by: Cursor --- README.md | 4 ++-- action.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2baa701..5eea786 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Code Discovery GitHub Action -Scans your repository with the Surface CLI (`apisec-code-bolt`) and uploads the result to APIsec. Existing Code Discovery apps are updated in place. +Scans your repository with the Surface CLI (`apisec-surface`) and uploads the result to APIsec. Existing Code Discovery apps are updated in place. Ship this cutover as **`v1.0.0`** / **`v1`**. Keep **`v0.1.8`** pinned if you need to roll back to Code Discovery. @@ -65,7 +65,7 @@ The Action never fails the workflow. Check `success` if a later step should stop ## How it works -1. Installs Python 3.11 and Surface CLI `0.1.11` +1. Installs Python 3.11 and Surface CLI `0.1.13` 2. Registers or reuses one APIsec application per GitHub repo (`github:`) 3. Uploads the Surface manifest; the reasoning engine publishes the OpenAPI spec diff --git a/action.yml b/action.yml index 890d99a..9078ce9 100644 --- a/action.yml +++ b/action.yml @@ -73,8 +73,8 @@ runs: shell: bash run: | python -m pip install --upgrade pip - pip install "apisec-code-bolt==0.1.10" - apisec-code-bolt telemetry off || true + pip install "apisec-surface==0.1.13" + apisec-surface telemetry off || true - name: Run Surface discovery id: discovery @@ -104,7 +104,7 @@ runs: ARGS+=(--dry-run) fi set +e - apisec-code-bolt "${ARGS[@]}" 2> >(tee scan.ndjson >&2) + apisec-surface "${ARGS[@]}" 2> >(tee scan.ndjson >&2) RC=$? set -e From 61203b04f8a1985215ccadd8f4df38e47d54e1a7 Mon Sep 17 00:00:00 2001 From: Humera-Yameen Date: Thu, 8 Oct 2026 18:10:50 +1100 Subject: [PATCH 4/5] fix: pin apisec-surface 1.0.0, fix log capture race, customer-ready README Rollback tag is v0.1.9. Lists Surface frameworks and notes Gin/Argos stay on v0.1.x. CI now asserts success. Co-authored-by: Cursor --- .github/workflows/test-action.yml | 6 ++-- README.md | 55 ++++++++++++++++++++----------- action.yml | 7 ++-- 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml index 8daa40e..584a080 100644 --- a/.github/workflows/test-action.yml +++ b/.github/workflows/test-action.yml @@ -25,8 +25,10 @@ jobs: api-token: ${{ secrets.API_DISCOVERY_TOKEN || 'test-token' }} dry-run: 'true' - - name: Display outputs + - name: Check outputs run: | - echo "Spec path: ${{ steps.discovery.outputs.spec-path }}" echo "Success: ${{ steps.discovery.outputs.success }}" + echo "Endpoints: ${{ steps.discovery.outputs.endpoints-count }}" + echo "Frameworks: ${{ steps.discovery.outputs.frameworks-detected }}" + test "${{ steps.discovery.outputs.success }}" = "true" diff --git a/README.md b/README.md index 5eea786..29079dc 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ -# Code Discovery GitHub Action +# APIsec Surface GitHub Action -Scans your repository with the Surface CLI (`apisec-surface`) and uploads the result to APIsec. Existing Code Discovery apps are updated in place. +Scans your repository with the Surface CLI ([`apisec-surface`](https://pypi.org/project/apisec-surface/)) and uploads the result to APIsec. Surface replaces Code Discovery / Code Bolt; applications created by Code Discovery are updated in place. -Ship this cutover as **`v1.0.0`** / **`v1`**. Keep **`v0.1.8`** pinned if you need to roll back to Code Discovery. +## Quick start -## Usage +1. Add two repository secrets (Settings → Secrets and variables → Actions): + - `API_DISCOVERY_ENDPOINT`: your APIsec API URL, for example `https://api.apisecapps.com` + - `API_DISCOVERY_TOKEN`: an APIsec personal access token with the `app:create` permission +2. Add `.github/workflows/api-discovery.yml`: ```yaml name: API Discovery @@ -24,7 +27,7 @@ jobs: api-token: ${{ secrets.API_DISCOVERY_TOKEN }} ``` -`api-endpoint` is the applicationsservice base URL (the same value Surface uses as `--api-url`). +Existing Code Discovery workflows only need the tag changed to `@v1`. The `contents: write` and `pull-requests: write` permissions are no longer needed. ### Dry run @@ -40,24 +43,24 @@ jobs: | Input | Required | Default | Description | |-------|----------|---------|-------------| -| `api-endpoint` | Yes | | APIsec applicationsservice base URL | +| `api-endpoint` | Yes | | APIsec API URL | | `api-token` | Yes | | APIsec personal access token | | `repo-path` | No | `.` | Repository root to analyze | -| `dry-run` | No | `false` | Analyse only; do not upload | +| `dry-run` | No | `false` | Analyze only; do not upload | | `config-path` | No | `.codediscovery.yml` | Ignored | -| `host-url` | No | | Ignored — set the instance host in the APIsec console | -| `pr-title` | No | | Ignored — no spec PR is opened | -| `pr-body` | No | | Ignored — no spec PR is opened | +| `host-url` | No | | Ignored; set the instance host in the APIsec console | +| `pr-title` | No | | Ignored; no spec PR is opened | +| `pr-body` | No | | Ignored; no spec PR is opened | ## Outputs | Output | Description | |--------|-------------| -| `success` | `true` only when the CLI exited 0 | +| `success` | `true` only when the scan completed | | `application-id` | APIsec application id after a successful upload | | `endpoints-count` | Number of API routes found | | `frameworks-detected` | Comma-separated frameworks | -| `spec-path` | Empty (spec is published by the engine) | +| `spec-path` | Empty (the spec is published by APIsec) | | `instance-id` | Empty | | `pr-url` | Empty | @@ -65,17 +68,29 @@ The Action never fails the workflow. Check `success` if a later step should stop ## How it works -1. Installs Python 3.11 and Surface CLI `0.1.13` -2. Registers or reuses one APIsec application per GitHub repo (`github:`) -3. Uploads the Surface manifest; the reasoning engine publishes the OpenAPI spec +1. Installs Python 3.11 and Surface CLI `1.0.0` +2. Registers or reuses one APIsec application per GitHub repository +3. Uploads the Surface analysis; APIsec publishes the OpenAPI spec -Set the instance host URL in the APIsec console after the first run if the default `/` is not your API base. +After the first run, set the instance host URL in the APIsec console if the default `/` is not your API base. -## Requirements +## Changes from Code Discovery (`v0.1.x`) -- Python 3.11 (installed by the Action) -- An APIsec PAT with `app:create` +- No pull request is opened and no files are committed to your repository. +- `host-url`, `config-path`, `pr-title` and `pr-body` are accepted but ignored. +- `spec-path`, `instance-id` and `pr-url` outputs are empty. + +## Supported frameworks + +- **Java**: Spring Boot, Micronaut, JAX-RS (Jersey, Quarkus, RESTEasy), Servlet +- **Python**: FastAPI, Flask, Django +- **JavaScript / TypeScript**: Express, NestJS, Fastify, Koa +- **.NET**: ASP.NET Core, ASP.NET MVC / Web API, Web Forms, gRPC, WCF +- **Ruby**: Rails, Sinatra, Grape, Hanami, Roda, Padrino +- **GraphQL** + +Go (Gin) and Argos are not yet supported in Surface. Keep those repositories on `@v0.1.9` until they are. ## Rollback -Pin `@v0.1.8` to run Code Discovery again. +Pin `@v0.1.9` to run Code Discovery again. diff --git a/action.yml b/action.yml index 9078ce9..ab06257 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,6 @@ name: 'Code Discovery - API Discovery' description: 'Discover API endpoints with Surface CLI and upload them to APIsec' -author: 'APIsec Bolt' +author: 'APIsec' branding: icon: 'search' @@ -73,7 +73,7 @@ runs: shell: bash run: | python -m pip install --upgrade pip - pip install "apisec-surface==0.1.13" + pip install "apisec-surface==1.0.0" apisec-surface telemetry off || true - name: Run Surface discovery @@ -104,9 +104,10 @@ runs: ARGS+=(--dry-run) fi set +e - apisec-surface "${ARGS[@]}" 2> >(tee scan.ndjson >&2) + apisec-surface "${ARGS[@]}" 2>scan.ndjson RC=$? set -e + cat scan.ndjson >&2 RC="$RC" python - <<'PY' import json From c6be334f6add5e3b9fa2a5ec603d04d4c0a8c887 Mon Sep 17 00:00:00 2001 From: Humera-Yameen Date: Thu, 8 Oct 2026 18:42:28 +1100 Subject: [PATCH 5/5] fix: surface a workflow warning when the scan or upload fails Co-authored-by: Cursor --- action.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/action.yml b/action.yml index ab06257..2a22d36 100644 --- a/action.yml +++ b/action.yml @@ -108,6 +108,9 @@ runs: RC=$? set -e cat scan.ndjson >&2 + if [ "$RC" != "0" ]; then + echo "::warning title=APIsec Surface::Scan or upload failed (exit code $RC); results were not sent to APIsec. See the step log for details." + fi RC="$RC" python - <<'PY' import json