Skip to content
Merged
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
34 changes: 0 additions & 34 deletions .github/CODEOWNERS

This file was deleted.

6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
41 changes: 41 additions & 0 deletions .github/workflows/agent-skills-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Agent Skills CI

on:
pull_request:
paths:
- '.github/workflows/agent-skills-ci.yml'
- 'package.json'
- 'package-lock.json'
- 'packages/agent-skills/**'
push:
branches:
- master
paths:
- '.github/workflows/agent-skills-ci.yml'
- 'package.json'
- 'package-lock.json'
- 'packages/agent-skills/**'

permissions:
contents: read

jobs:
validate-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20

- name: Install dependencies
run: npm ci --workspace @oracle/agent-skills

- name: Validate Agent Skills
run: npm run validate --workspace @oracle/agent-skills

- name: Run tests
run: npm run test --workspace @oracle/agent-skills
54 changes: 54 additions & 0 deletions .github/workflows/ai-plugins-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: AI Agent Plug-ins CI

on:
pull_request:
paths:
- '.github/workflows/ai-plugins-ci.yml'
- 'package.json'
- 'package-lock.json'
- '.gitignore'
- 'LICENSE.txt'
- 'packages/ai-plugins/**'
- 'packages/agent-skills/**'
push:
branches:
- master
paths:
- '.github/workflows/ai-plugins-ci.yml'
- 'package.json'
- 'package-lock.json'
- '.gitignore'
- 'LICENSE.txt'
- 'packages/ai-plugins/**'
- 'packages/agent-skills/**'

permissions:
contents: read

jobs:
validate-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
persist-credentials: false

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20

- name: Install dependencies
run: npm ci --workspace @oracle/ai-plugins

- name: Validate plugin configuration
run: npm run validate --workspace @oracle/ai-plugins

- name: Run tests
run: npm run test --workspace @oracle/ai-plugins

- name: Build plugin directories
run: npm run build --workspace @oracle/ai-plugins

- name: Verify release output matches source build
run: npm run verify-release --workspace @oracle/ai-plugins
217 changes: 217 additions & 0 deletions .github/workflows/ai-plugins-dist.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
name: Publish AI Agent Plug-ins Dist

on:
workflow_dispatch:

concurrency:
group: ai-plugins-dist-release
cancel-in-progress: false

permissions:
contents: read

jobs:
prepare:
if: github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
outputs:
publish_required: ${{ steps.release-metadata.outputs.publish_required }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
persist-credentials: false

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20

- name: Check GitHub Actions workflow policy
run: node packages/ai-plugins/scripts/release-security-gates.mjs workflows .github/workflows

- name: Scan source for secrets
run: node packages/ai-plugins/scripts/release-security-gates.mjs secrets .

- name: Audit locked dependencies
run: npm audit --package-lock-only --audit-level=high

- name: Install dependencies
run: npm ci --workspace @oracle/agent-skills --workspace @oracle/ai-plugins

- name: Validate Agent Skills
run: npm run validate --workspace @oracle/agent-skills

- name: Validate plugin configuration
run: npm run validate --workspace @oracle/ai-plugins

- name: Run tests
run: |
npm run test --workspace @oracle/agent-skills
npm run test --workspace @oracle/ai-plugins

- name: Build plugin directories
run: npm run build --workspace @oracle/ai-plugins

- name: Scan generated distribution for secrets
run: node packages/ai-plugins/scripts/release-security-gates.mjs secrets dist/ai-plugins

- name: Verify release output matches source build
run: npm run verify-release --workspace @oracle/ai-plugins

- name: Create release integrity manifest
run: node packages/ai-plugins/scripts/release-integrity.mjs create dist/ai-plugins release-metadata/ai-plugins-dist.sha256

- name: Determine release metadata
id: release-metadata
shell: bash
env:
DIST_BRANCH: ai-plugins-dist
GITHUB_TOKEN: ${{ github.token }}
run: |
set -euo pipefail

previous_dir="$(mktemp -d)"
metadata_dir="release-metadata"
publish_required=false
mkdir -p "${metadata_dir}"
: > "${metadata_dir}/changed-plugins.tsv"
trap 'rm -rf "${previous_dir}"' EXIT

# The read-scoped token is limited to this step and is never persisted
# in Git configuration. Only ls-remote status 2 confirms that the
# distribution branch is absent; authentication and transport errors
# must stop metadata generation.
remote_url="https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
if git ls-remote --exit-code "${remote_url}" "refs/heads/${DIST_BRANCH}" >/dev/null; then
git fetch --no-tags "${remote_url}" \
"refs/heads/${DIST_BRANCH}:refs/remotes/origin/${DIST_BRANCH}"
git archive "refs/remotes/origin/${DIST_BRANCH}" | tar -x -C "${previous_dir}"
else
ls_remote_status=$?
if [ "${ls_remote_status}" -eq 2 ]; then
echo "Distribution branch does not exist yet; preparing initial release."
else
echo "Failed to determine whether distribution branch exists (git ls-remote exited ${ls_remote_status})." >&2
exit "${ls_remote_status}"
fi
fi

while IFS= read -r manifest_path; do
plugin_dir="$(dirname "$(dirname "${manifest_path}")")"
plugin_name="${plugin_dir#dist/ai-plugins/}"
previous_plugin_dir="${previous_dir}/${plugin_name}"

if ! diff -qr "${plugin_dir}" "${previous_plugin_dir}" >/dev/null 2>&1; then
version="$(node packages/ai-plugins/scripts/release-version.mjs --allow-same-version-republish "${plugin_dir}" "${previous_plugin_dir}")"
printf '%s\t%s\n' "${plugin_name}" "${version}" >> "${metadata_dir}/changed-plugins.tsv"
publish_required=true
fi
done < <(find dist/ai-plugins -type f \( -path '*/.claude-plugin/plugin.json' -o -path '*/.codex-plugin/plugin.json' \) | sort)

while IFS= read -r previous_manifest_path; do
previous_plugin_dir="$(dirname "$(dirname "${previous_manifest_path}")")"
previous_plugin_name="${previous_plugin_dir#${previous_dir}/}"
if [ ! -d "dist/ai-plugins/${previous_plugin_name}" ]; then
publish_required=true
fi
done < <(find "${previous_dir}" -type f \( -path '*/.claude-plugin/plugin.json' -o -path '*/.codex-plugin/plugin.json' \) | sort)

if ! cmp -s dist/ai-plugins/README.md "${previous_dir}/README.md"; then
publish_required=true
fi

printf '%s\n' "${GITHUB_SHA}" > "${metadata_dir}/source-sha"
printf '%s\n' "${publish_required}" > "${metadata_dir}/publish-required"
echo "publish_required=${publish_required}" >> "${GITHUB_OUTPUT}"

- name: Upload verified distribution output
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: verified-ai-plugins-dist
path: dist/ai-plugins
include-hidden-files: true
if-no-files-found: error

- name: Upload release metadata
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ai-plugins-release-metadata
path: release-metadata
if-no-files-found: error

publish:
needs: prepare
if: github.ref == 'refs/heads/master' && needs.prepare.result == 'success' && needs.prepare.outputs.publish_required == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout release integrity verifier
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: Download verified distribution output
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: verified-ai-plugins-dist
path: dist/ai-plugins

- name: Download release metadata
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: ai-plugins-release-metadata
path: release-metadata

- name: Verify downloaded distribution integrity
run: node packages/ai-plugins/scripts/release-integrity.mjs verify dist/ai-plugins release-metadata/ai-plugins-dist.sha256

- name: Publish verified distribution to ai-plugins-dist
shell: bash
env:
DIST_BRANCH: ai-plugins-dist
GITHUB_TOKEN: ${{ github.token }}
run: |
set -euo pipefail

source_sha="$(<release-metadata/source-sha)"
test "$(<release-metadata/publish-required)" = true
worktree_dir="$(mktemp -d)"
trap 'rm -rf "${worktree_dir}"' EXIT

# All repository-controlled commands completed in prepare. Configure
# the write-scoped token only for this final fetch/push/tag sequence.
git init "${worktree_dir}"
git -C "${worktree_dir}" config user.name "github-actions[bot]"
git -C "${worktree_dir}" config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git -C "${worktree_dir}" remote add origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"

if git -C "${worktree_dir}" fetch --no-tags origin "${DIST_BRANCH}:${DIST_BRANCH}"; then
git -C "${worktree_dir}" checkout "${DIST_BRANCH}"
else
git -C "${worktree_dir}" checkout --orphan "${DIST_BRANCH}"
git -C "${worktree_dir}" rm -rf --ignore-unmatch .
fi

while IFS=$'\t' read -r plugin_name version; do
[ -n "${plugin_name}" ] || continue
tag="ai-plugin/${plugin_name}/v${version}"
if git -C "${worktree_dir}" ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null; then
echo "Refusing to publish because release tag already exists: ${tag}" >&2
exit 1
fi
done < release-metadata/changed-plugins.tsv

git -C "${worktree_dir}" rm -rf --ignore-unmatch .
cp -R dist/ai-plugins/. "${worktree_dir}/"

git -C "${worktree_dir}" add -A
git -C "${worktree_dir}" commit -m "Publish AI plugins from ${source_sha}"
git -C "${worktree_dir}" push origin "HEAD:${DIST_BRANCH}"

while IFS=$'\t' read -r plugin_name version; do
[ -n "${plugin_name}" ] || continue
tag="ai-plugin/${plugin_name}/v${version}"
git -C "${worktree_dir}" tag -a "${tag}" -m "Release ${plugin_name} v${version}" HEAD
git -C "${worktree_dir}" push origin "${tag}"
done < release-metadata/changed-plugins.tsv
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ packages/sdk-core/*.tsbuildinfo
# packaged release artifacts
/dist/

# distribution files for ai-plugins
dist/ai-plugins/

# coverage reports
**/coverage/**

Expand Down
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ Only pull requests from contributors who can be verified as having signed the OC
your changes. Ensure that you reference the issue you created as well.
7. We will assign the pull request to 2-3 people for review before it is merged.

## Workflow Dependency Review

When reviewing a pull request that changes a GitHub Actions dependency, confirm:

1. The action uses the expected upstream owner and repository.
2. The pinned commit SHA maps to the stated upstream release or tag and has GitHub provenance.
3. The version comment next to the SHA is retained.
4. Required CI checks pass before the pull request is merged.

## Code of Conduct

Follow the [Golden Rule](https://en.wikipedia.org/wiki/Golden_Rule). For more specific guidelines, see the [Contributor Covenant Code of Conduct][COC].
Expand Down
Loading
Loading