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
96 changes: 96 additions & 0 deletions .github/workflows/assemble_tools_json.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Assemble tools.json

on:
push:
branches: [ 'master', 'main' ]
paths:
- "tools/*"
- ".github/workflows/assemble_tools_json.yml"
workflow_dispatch:

# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
permissions: { }

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
assemble:
name: assemble tools.json
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.x
- name: assemble tools.json
run: helpers/tools-assemble.py
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: tools.json
path: tools.json

validate:
needs:
- assemble
name: validate tools.json
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Install check-jsonschema
run: pip install check-jsonschema
- name: Download artifact
uses: actions/download-artifact@v5
with:
name: tools.json
- name: Validate tools.json
run: check-jsonschema --schemafile schemas/tools.schema.json tools.json

push-back:
needs:
- assemble
- validate
name: push tools.json
runs-on: ubuntu-latest
permissions:
contents: write # needed for git push
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
ref: ${{ github.head_ref }}
- name: Download artifact
uses: actions/download-artifact@v5
with:
name: tools.json
- name: diff
run: git diff tools.json
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Commit tools.json
run: |
git add tools.json
git commit -s -m "Update tools.json [automated commit]" || echo "No changes to commit"
- name: git push back
run: git push

publish:
needs:
- push-back
# need to trigger this workflow manually, for the following reason:
# The "publish" workflow is triggered whenever a `tools.json` is modified - which happens during
# the `push-back` step. and this commit is issued by a bot.
# GitHub workflows may triggered on events only if not issues by a bot - so the workflow would
# not trigger automatically.
uses: .github/workflows/publish_toolcenter.yml
16 changes: 8 additions & 8 deletions .github/workflows/build_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ name: Build Docs
on:
push:
branches: ['master', 'main']
paths:
- "schemas/*"
- ".github/workflows/build_docs.yml"
workflow_dispatch:

env:
PYTHON_VERSION_DEFAULT: "3.10"

# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
docs_json:
runs-on: ubuntu-latest
Expand All @@ -24,8 +28,7 @@ jobs:
- name: Setup Python Environment
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION_DEFAULT }}
architecture: 'x64'
python-version: 3.x

- name: Generate Schema documentation
run: ./gen.sh
Expand All @@ -45,6 +48,3 @@ jobs:
steps:
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v4

- name: Trigger Cloudflare Deploy Hook
run: curl -X POST "${{ secrets.CLOUDFLARE_DEPLOY_HOOK }}"
23 changes: 23 additions & 0 deletions .github/workflows/publish_toolcenter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: publish ToolCenter

on:
push:
branches: [ 'master', 'main' ]
paths:
- "tools.json"
- ".github/workflows/publish_toolcenter.yml"
workflow_dispatch:

# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
permissions: { }

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
trigger_deploy:
runs-on: ubuntu-latest
steps:
- name: Trigger Cloudflare Deploy Hook
run: curl -X POST "${{ secrets.CLOUDFLARE_DEPLOY_HOOK }}"
42 changes: 42 additions & 0 deletions .github/workflows/validate_tools.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Validate each tool

on:
push:
branches: [ 'master', 'main' ]
paths:
- "tools/*"
- "schemas/tool.schema.json"
- ".github/workflows/validate_tools.yml"
pull_request:
paths:
- "tools/*"
- "schemas/tool.schema.json"
- ".github/workflows/validate_tools.yml"
workflow_dispatch:

# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
permissions: { }

jobs:
validate:
name: validate each tool
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.x

- name: Install check-jsonschema
run: pip install check-jsonschema

- name: Validate all tools
run: |
set -exu
for tool in tools/*.json
do
check-jsonschema --schemafile schemas/tool.schema.json "$tool"
done
18 changes: 13 additions & 5 deletions .github/workflows/validate_tools_json.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,28 @@ name: Validate tools.json

on:
push:
paths: [ "tools.json", "tools.schema.json", ".github/workflows/validate_tools_json.yml" ]
branches: [ 'master', 'main' ]
paths:
- "tools.json"
- "schemas/tools.schema.json"
- ".github/workflows/validate_tools_json.yml"
pull_request:
paths: [ "tools.json", "tools.schema.json", ".github/workflows/validate_tools_json.yml" ]
branches: [ 'master', 'main' ]
paths:
- "tools.json"
- "schemas/tools.schema.json"
- ".github/workflows/validate_tools_json.yml"
workflow_dispatch:

# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
permissions: {}
permissions: { }

jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Set up Python
uses: actions/setup-python@v5
Expand All @@ -26,4 +34,4 @@ jobs:
run: pip install check-jsonschema

- name: Validate tools.json
run: check-jsonschema --schemafile tools.schema.json tools.json
run: check-jsonschema --schemafile schemas/tools.schema.json tools.json
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

The CycloneDX Tool Center is the largest publicly available collection of SBOM (Software Bill of Materials) and xBOM (e.g., SaaSBOM, CBOM, HBOM) products, projects, and services. It serves as a centralized resource for anyone looking to explore, evaluate, or integrate BOM-related capabilities into their toolchains and workflows. The Tool Center is an integral part of the [CycloneDX website](https://cyclonedx.org).

As of March 2025, the CycloneDX Tool Center leverages a JSON Schema in which `tools.json` must validate against. [View the human-readable documentation for the JSON Schema](https://cyclonedx.github.io/tool-center/).
As of March 2025, the CycloneDX Tool Center leverages a JSON Schema in which `tools.json` must validate against. [View the human-readable documentation for the JSON Schema](https://cyclonedx.github.io/tool-center/).
As of September 2025, the `tools.json` is assembled automatically from the individual JSON files in the `tools/` folder. Do not modify `tools.json` directly, instead add/modify individual files in the `tools/`folder.

## License

Expand All @@ -16,8 +17,8 @@ Contributions are welcome! If you know of a tool, product, or service related to
- Any provided metadata or descriptions are accurate and up-to-date.
- Licensing and attribution requirements for tools are respected.

Editing the `tools.json` file manually can be complicated. An alternative is to use
[MetaConfigurator](https://metaconfigurator.github.io/meta-configurator/?schema=https://raw.githubusercontent.com/CycloneDX/tool-center/refs/heads/main/tools.schema.json&data=https://raw.githubusercontent.com/CycloneDX/tool-center/refs/heads/main/tools.json&settings=https://raw.githubusercontent.com/CycloneDX/tool-center/refs/heads/main/metaConfiguratorSettings.json) to make changes then download the edited data.
Creating/editing a file in the `tools/` folder manually can be complicated. An alternative is to use
[MetaConfigurator](https://www.metaconfigurator.org?schema=https://raw.githubusercontent.com/CycloneDX/tool-center/refs/heads/main/schemas/tool.schema.json&settings=https://raw.githubusercontent.com/CycloneDX/tool-center/refs/heads/main/metaConfiguratorSettings.json) to make changes then download the edited data.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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


## Community & Support

Expand Down
48 changes: 31 additions & 17 deletions docgen/gen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ DESC="Generate HTML Schema navigator for CycloneDX Tool Center"

# Paths (adjust if needed)
THIS_PATH="$(realpath "$(dirname "$0")")"
SCHEMA_PATH="$(realpath "$THIS_PATH/..")"
SCHEMA_PATH="$(realpath "$THIS_PATH/../schemas")"
DOCS_PATH="$THIS_PATH/docs"
TEMPLATES_PATH="$THIS_PATH/templates"

Expand All @@ -18,18 +18,15 @@ prepare () {
fi
}

generate () {
local title="CycloneDX Tool Center JSON Reference"
echo "Generating: $title"

local SCHEMA_FILE="$SCHEMA_PATH/tools.schema.json"
echo "SCHEMA_FILE: $SCHEMA_FILE"
clean () {
rm -rf "$DOCS_PATH"
mkdir -p "$DOCS_PATH"
}

local OUT_FILE="$DOCS_PATH/index.html"
local OUT_DIR
OUT_DIR="$(dirname "$OUT_FILE")"
rm -rf "$OUT_DIR"
mkdir -p "$OUT_DIR"
_generate () {
local title="$1"
local schema_file="$2"
local out_file="$3"

# Generate HTML documentation from the JSON schema
generate-schema-doc \
Expand All @@ -40,16 +37,33 @@ generate () {
--config title="$title" \
--config custom_template_path="$TEMPLATES_PATH/cyclonedx/base.html" \
--minify \
"$SCHEMA_FILE" \
"$OUT_FILE"
"$schema_file" \
"$out_file"

# Update placeholders in the generated HTML
sed -i -e "s/\${quotedTitle}/\"$title\"/g" "$OUT_FILE"
sed -i -e "s/\${title}/$title/g" "$OUT_FILE"
sed -i -e "s/\${quotedTitle}/\"$title\"/g" "$out_file"
sed -i -e "s/\${title}/$title/g" "$out_file"
}


generate_tools () {
_generate \
"CycloneDX Tool Center v2 - Tools - JSON Reference"\
"$SCHEMA_PATH/tools.schema.json" \
"$DOCS_PATH/index.html"
}

generate_tool () {
_generate \
"CycloneDX Tool Center v2 - Tool - JSON Reference"\
"$SCHEMA_PATH/tool.schema.json" \
"$DOCS_PATH/tool.html"
}

# Main
prepare
generate
clean
generate_tools
generate_tool

exit 0
11 changes: 11 additions & 0 deletions docgen/templates/cyclonedx/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarScroll" aria-controls="navbarScroll" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarScroll">
<ul class="navbar-nav mr-auto my-2 my-lg-0 navbar-nav-scroll" style="max-height: 100px;">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarScrollingDropdown" role="button" data-toggle="dropdown" aria-expanded="false">select a schema</a>
<ul class="dropdown-menu" aria-labelledby="navbarScrollingDropdown">
<li><a class="dropdown-item" href="index.html">Tools</a></li>
<li><a class="dropdown-item" href="tool.html">Tool</a></li>
</ul>
</li>
</ul>
</div>
</nav>


Expand Down
36 changes: 36 additions & 0 deletions helpers/tools-assemble.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env python3

from datetime import datetime, timezone
from json import dump as json_dump, load as json_load
from pathlib import Path

REPO_ROOT = Path(__file__).parent.parent
TOOLS_JSON = REPO_ROOT / 'tools.json'
TOOLS_FOLDER = REPO_ROOT / 'tools'

tools = []

license_ = {
'id': 'CC-BY-SA-4.0',
'name': 'Creative Commons Attribution-ShareAlike 4.0 International',
'url': 'https://creativecommons.org/licenses/by-sa/4.0/'
}

now = datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace('+00:00', 'Z')

for tfn in sorted(TOOLS_FOLDER.glob('*.json')):
print('loading', tfn, '...')
with open(tfn) as t:
tool = json_load(t)
tool['tool']['_fromFile'] = tfn.name
tools.append(tool['tool'])

print('writing', TOOLS_JSON, '...')
with open(TOOLS_JSON, 'w') as ts:
json_dump({
'$schema': 'https://cyclonedx.org/schema/tool-center-v2.schema.json',
'specVersion': '2.0',
'last_updated': now,
'license': license_,
'tools': tools
}, ts, indent=2)
Loading