diff --git a/CLAUDE.md b/CLAUDE.md
index b9dac8a..c3fae29 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,7 +1,7 @@
# IcebergSCA — maintenance notes
-CLI for supply chain analysis: walk a project, find manifests and lockfiles, resolve the
-dependency graph, check every package against OSV, report it.
+CLI for software composition analysis: walk a project, find manifests and lockfiles, resolve
+the dependency graph, check every package against OSV, report it.
## Commands
@@ -126,7 +126,7 @@ project's build to discover its dependencies is itself a supply chain risk.
`MavenResolver._backfill` re-reads `pom.xml` to apply BOM-supplied versions to direct dependencies,
which the synchronous parser cannot do because BOMs live on Central.
-**Ranges, SARIF and CycloneDX are hand-written** rather than pulled from packages — a supply chain
+**Ranges, SARIF and CycloneDX are hand-written** rather than pulled from packages — a dependency
scanner with a large dependency tree of its own is a poor advertisement. Correctness is held by
schema validation in `tests/test_report_formats.py` against the official schemas in `tests/schemas/`.
diff --git a/README.md b/README.md
index fbaea72..1f11e18 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,12 @@
# IcebergSCA
-Supply chain analysis for software projects. Point it at a directory; it finds every
-dependency manifest and lockfile, builds the direct and transitive dependency set, looks each
-package up in [OSV](https://osv.dev), and reports what it finds.
+Software composition analysis (SCA) for software projects. Point it at a directory; it finds
+every dependency manifest and lockfile, builds the direct and transitive dependency set, looks
+each package up in [OSV](https://osv.dev), and reports what it finds.
+
+It inventories the third-party components a project declares; it does not read first-party
+source code, and it identifies a package by name and version rather than by what the
+downloaded artefact contains.
Documentation:
@@ -47,8 +51,8 @@ lockfile is present does it fall back to resolving version ranges against the re
those findings are labelled `resolved` rather than `pinned`. Java, which has no lockfile, gets
its graph reconstructed from Maven Central and is marked `~` for approximate.
-**It never claims to be clean when it isn't.** This is the design constraint everything else
-bends around:
+**A clean result is never implied unless it was earned.** Most of the rest of the design
+follows from this:
- An empty findings list because the lookup never ran is reported as *"vulnerability lookup did
not run"*, never as *"no vulnerabilities found"*. The JSON carries an explicit
@@ -60,7 +64,7 @@ bends around:
are declared rather than installed.
- Skipped files, truncated graphs and unresolved constraints are all counted and shown.
-**Findings never fail your build.**
+**Findings do not change the exit code.**
| Exit code | Meaning |
|---|---|
@@ -119,10 +123,9 @@ icebergsca/.agents/skills/icebergsca/SKILL.md
```
Agents that glob site-packages for `SKILL.md` will find it automatically after install. It
-covers invocation, the JSON schema, exit-code semantics, and — most importantly — the three
-fields that must be checked before reporting a project as clean. An empty `findings` array
-means "checked and clean", "never checked" or "partially checked", and only the report can say
-which.
+covers invocation, the JSON schema, exit-code semantics, and the three fields to check before
+reporting a project as clean. An empty `findings` array means "checked and clean", "never
+checked" or "partially checked", and only the report can say which.
## Caching
diff --git a/pyproject.toml b/pyproject.toml
index 712cfb5..fe1003f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
[project]
name = "icebergsca"
version = "0.1.0"
-description = "Supply chain analysis for software projects — lockfile-first dependency scanning against OSV"
+description = "Software composition analysis for software projects — lockfile-first dependency scanning against OSV"
readme = "README.md"
requires-python = ">=3.11"
# PEP 639: an SPDX expression plus the files to bundle. A "License ::" classifier
@@ -13,7 +13,17 @@ requires-python = ">=3.11"
license = "Apache-2.0"
license-files = ["LICENSE", "NOTICE"]
authors = [{ name = "Richard Hope" }]
-keywords = ["sca", "supply-chain", "security", "osv", "sbom", "cyclonedx", "vulnerabilities"]
+keywords = [
+ "sca",
+ "software-composition-analysis",
+ "dependency-scanning",
+ "supply-chain",
+ "security",
+ "osv",
+ "sbom",
+ "cyclonedx",
+ "vulnerabilities",
+]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Console",
diff --git a/src/icebergsca/.agents/skills/icebergsca/SKILL.md b/src/icebergsca/.agents/skills/icebergsca/SKILL.md
index 95172ae..4260855 100644
--- a/src/icebergsca/.agents/skills/icebergsca/SKILL.md
+++ b/src/icebergsca/.agents/skills/icebergsca/SKILL.md
@@ -1,11 +1,11 @@
---
name: icebergsca
-description: IcebergSCA usage and output interpretation. Use when scanning a project for vulnerable dependencies, auditing a supply chain, generating an SBOM, or reading an IcebergSCA report. Covers the JSON schema, exit codes, and the checks required before reporting a project as clean.
+description: IcebergSCA usage and output interpretation. Use when scanning a project for vulnerable dependencies, performing software composition analysis, generating an SBOM, or reading an IcebergSCA report. Covers the JSON schema, exit codes, and the checks required before reporting a project as clean.
---
# IcebergSCA
-Official IcebergSCA skill for running supply chain scans and reading the results correctly.
+Official IcebergSCA skill for running dependency scans and reading the results correctly.
IcebergSCA walks a project, finds every dependency manifest and lockfile, resolves the
dependency graph, checks each package against [OSV](https://osv.dev), and reports findings.
diff --git a/src/icebergsca/.agents/skills/icebergsca/references/ci-integration.md b/src/icebergsca/.agents/skills/icebergsca/references/ci-integration.md
index 4e9708f..085981e 100644
--- a/src/icebergsca/.agents/skills/icebergsca/references/ci-integration.md
+++ b/src/icebergsca/.agents/skills/icebergsca/references/ci-integration.md
@@ -55,7 +55,7 @@ Notes on the SARIF we emit:
## Full workflow
```yaml
-name: Supply chain
+name: Dependency scan
on:
push: { branches: [main] }
@@ -86,8 +86,8 @@ jobs:
category: icebergsca
```
-The scheduled run matters more than it looks: most new findings arrive because an advisory was
-published, not because the code changed.
+The scheduled run matters: most new findings arrive because an advisory was published, not
+because the code changed.
## SBOM artefacts
diff --git a/src/icebergsca/__init__.py b/src/icebergsca/__init__.py
index 4321fe6..132f971 100644
--- a/src/icebergsca/__init__.py
+++ b/src/icebergsca/__init__.py
@@ -1,3 +1,3 @@
-"""IcebergSCA — supply chain analysis for software projects."""
+"""IcebergSCA — software composition analysis for software projects."""
__version__ = "0.1.0"
diff --git a/src/icebergsca/cli/main.py b/src/icebergsca/cli/main.py
index c724a9a..e29e5e5 100644
--- a/src/icebergsca/cli/main.py
+++ b/src/icebergsca/cli/main.py
@@ -48,7 +48,7 @@ class ExitCode(IntEnum):
app = typer.Typer(
name="icebergsca",
- help="Supply chain analysis: find dependencies, check them against OSV.",
+ help="Software composition analysis: find dependencies, check them against OSV.",
no_args_is_help=True,
add_completion=False,
)
diff --git a/src/icebergsca/core/models.py b/src/icebergsca/core/models.py
index 3968e22..cf76a4d 100644
--- a/src/icebergsca/core/models.py
+++ b/src/icebergsca/core/models.py
@@ -362,7 +362,7 @@ def sources(self) -> tuple[SourceLocation, ...]:
class SkippedFile:
"""A file we recognised but did not scan, and why.
- Skips are always reported. A supply chain tool that quietly drops a manifest is
+ Skips are always reported. A scanner that quietly drops a manifest is
indistinguishable from one that found nothing wrong with it.
"""
diff --git a/src/icebergsca/report/cyclonedx.py b/src/icebergsca/report/cyclonedx.py
index c10f41d..3bc2753 100644
--- a/src/icebergsca/report/cyclonedx.py
+++ b/src/icebergsca/report/cyclonedx.py
@@ -5,7 +5,7 @@
affected by CVE-2021-44228", which would mean shipping the interesting half of the
report in a separate file.
-Written by hand rather than through ``cyclonedx-python-lib``. A supply chain scanner
+Written by hand rather than through ``cyclonedx-python-lib``. A dependency scanner
that drags in a large dependency tree of its own is a poor advertisement for itself,
and the document is a few nested dictionaries. Correctness is held by validating the
output against the published schema in the test suite.
diff --git a/src/icebergsca/resolve/ranges.py b/src/icebergsca/resolve/ranges.py
index 8043d83..56ee7d6 100644
--- a/src/icebergsca/resolve/ranges.py
+++ b/src/icebergsca/resolve/ranges.py
@@ -6,8 +6,8 @@
ecosystem's job is reduced to expanding its own shorthand (``^``, ``~>``, ``[1.0,2.0)``)
into those bounds.
-Implemented here rather than pulled in from a semver package: this is a supply chain
-tool, and every dependency it takes on is one more thing its own users have to trust.
+Implemented here rather than pulled in from a semver package: every dependency this
+tool takes on is one more thing its own users have to trust.
Every entry point can return ``None``, meaning "this syntax is beyond us". That is
deliberately distinct from "nothing matched" — the caller marks such dependencies
diff --git a/website/README.md b/website/README.md
index 1cd7801..f2b7e40 100644
--- a/website/README.md
+++ b/website/README.md
@@ -28,7 +28,7 @@ Notes:
captures in `../docs/img/`. Regenerate those first, then re-copy.
- Nothing is loaded from a CDN: fonts are self-hosted (`font = false` disables
Google Fonts) and the mermaid fence is configured but deliberately unused,
- since the theme lazy-loads mermaid from unpkg. A supply chain scanner's own
- site should not quietly take a third-party runtime dependency.
+ since the theme lazy-loads mermaid from unpkg. The site for a dependency
+ scanner should not quietly take a third-party runtime dependency.
- `docs/stylesheets/iceberg.css` carries the family design tokens verbatim from
the Iceberg (CTI) sheet. Edit them there first, then copy across.
diff --git a/website/docs/agents.md b/website/docs/agents.md
index dc2af63..e499de8 100644
--- a/website/docs/agents.md
+++ b/website/docs/agents.md
@@ -25,7 +25,7 @@ always the version documented.
- [`references/ci-integration.md`](https://github.com/IcebergAI/IcebergSCA/blob/main/src/icebergsca/.agents/skills/icebergsca/references/ci-integration.md)
— SARIF, SBOM artefacts, gating and caching
-## The part that matters
+## Before reporting a project clean
An empty `findings` array means "checked and clean", "never checked" or
"partially checked" — and only the report can say which. The skill exists mostly
@@ -87,7 +87,7 @@ if not report["findings"]:
- **Escalate `malicious: true`.** An OSV `MAL-` advisory is a package published
to attack its consumers, not a bug. The remediation is removal, not upgrade.
-## Keeping it honest
+## How the skill is kept current
The skill is tested, not just written: `tests/test_skill.py` guards its
location, frontmatter and links, and asserts that
diff --git a/website/docs/assets/icebergsca-horizontal.svg b/website/docs/assets/icebergsca-horizontal.svg
index fe0355e..56df91c 100644
--- a/website/docs/assets/icebergsca-horizontal.svg
+++ b/website/docs/assets/icebergsca-horizontal.svg
@@ -16,4 +16,4 @@
- IcebergSCASupply chain analysis
+ IcebergSCASoftware composition analysis
diff --git a/website/docs/ecosystems.md b/website/docs/ecosystems.md
index a49e7ef..80b9e74 100644
--- a/website/docs/ecosystems.md
+++ b/website/docs/ecosystems.md
@@ -32,7 +32,7 @@ icebergsca scan . --ecosystem pypi,npm
reports carry the **OSV** name in `package.ecosystem` and the purl type
inside `package.purl`. Correlate on `purl`.
-## Caveats worth knowing
+## Caveats
### Go reads `go.mod`, never `go.sum`
@@ -49,8 +49,7 @@ exclusions. Not modelled: profiles, mirrors, relocation and version ranges.
Affected manifests carry `approximate: true`, and the table marks them `~`.
IcebergSCA never shells out to `mvn`. Running a project's own build in order to
-discover its dependencies is itself a supply chain risk, and a scanner is a
-strange place to take it.
+discover its dependencies is itself a supply chain risk.
Gradle sees only literal declarations — no version catalogues, no computed
versions.
diff --git a/website/docs/how-it-works.md b/website/docs/how-it-works.md
index bc693b1..462e417 100644
--- a/website/docs/how-it-works.md
+++ b/website/docs/how-it-works.md
@@ -9,6 +9,12 @@ A scan is five stages: **discover → parse → resolve → scan → report**. E
records what it could not do, and that record survives all the way into the
output.
+The analysis is composition analysis: it inventories the third-party components
+a project declares and checks each one against known advisories. It does not
+read first-party source code, and it identifies a package by name and version
+rather than by what the downloaded artefact actually contains — so build
+provenance, signatures and typosquats are outside what a report can speak to.
+
## The five stages
### 1. Discover
@@ -56,7 +62,7 @@ Every package is looked up in [OSV](https://osv.dev), in two passes.
`querybatch` returns advisory IDs; `GET /v1/vulns/{id}` returns the detail that
makes severity and fix versions possible.
-Two behaviours here matter more than they look:
+Two behaviours here are worth spelling out:
- **Alias merging is required, not cosmetic.** OSV returns one record per
database, so a single CVE arrives as both a GHSA and a PYSEC record — rendered
diff --git a/website/docs/index.md b/website/docs/index.md
index f93d919..86eee77 100644
--- a/website/docs/index.md
+++ b/website/docs/index.md
@@ -9,15 +9,13 @@ hide:
-
Supply chain analysis
-
-Find. Resolve. Check. Report.
+Software composition analysis
Point IcebergSCA at a directory. It finds every dependency manifest and
lockfile, builds the direct and transitive dependency set, looks each package up
-in **OSV**, and reports what it finds — including, precisely, everything it
-could **not** check.
+in **OSV**, and reports what it finds — including everything it could **not**
+check.
@@ -42,15 +40,11 @@ it to the dependency tree it is meant to be auditing.
{ .term }
-## The one rule
-
-A scanner is only worth running if you can trust its silence. Most of the design
-here follows from a single constraint: **never imply a clean result the tool did
-not earn.**
+## What an empty findings list means
-An empty findings list means one of three very different things — checked and
-clean, never checked, or partially checked — and only the report can say which.
-So IcebergSCA says which:
+An empty findings list means one of three different things — checked and clean,
+never checked, or partially checked — and only the report can say which. So the
+report says which:
- The OSV lookup not running is reported as *"vulnerability lookup did not
run"*, never as *"no vulnerabilities found"*. JSON carries an explicit
@@ -90,7 +84,7 @@ So IcebergSCA says which:
[:octicons-arrow-right-24: Ecosystem support](ecosystems.md)
-- :material-file-tree: __Real dependency graphs__
+- :material-file-tree: __Transitive dependency graphs__
---
@@ -111,13 +105,13 @@ So IcebergSCA says which:
[:octicons-arrow-right-24: Output and CI](output.md)
-- :material-gate-alert: __Findings never fail your build__
+- :material-gate-alert: __Findings never change the exit code__
---
Exit `0` means the scan completed, findings or not. A non-zero exit always
- means the tool could not do its job — so nobody ever appends `|| true` and
- silences genuine failures along with the noise.
+ means the tool could not do its job, which is what keeps `|| true` off the
+ end of the command and genuine failures visible.
[:octicons-arrow-right-24: Exit codes](output.md#exit-codes)
@@ -125,20 +119,20 @@ So IcebergSCA says which:
---
- A skill ships inside the wheel, the way FastAPI, Typer and SQLModel do.
- Agents that glob site-packages find it after install: invocation, the JSON
- schema, exit-code semantics, and the three fields to check before calling a
- project clean.
+ A skill ships inside the wheel, following the convention FastAPI, Typer and
+ SQLModel use. Agents that glob site-packages find it after install:
+ invocation, the JSON schema, exit-code semantics, and the three fields to
+ check before calling a project clean.
[:octicons-arrow-right-24: For AI agents](agents.md)
-## Built to be scanned as well as to scan
+## The tool's own dependencies
-A supply chain scanner with a large dependency tree of its own is a poor
+A dependency scanner with a large dependency tree of its own is a poor
advertisement. Ranges, SARIF and CycloneDX are hand-written rather than pulled
-from packages, correctness held by schema validation against the official
+from packages, with correctness held by schema validation against the official
schemas. Maven graphs are reconstructed from Central rather than shelling out to
`mvn`, because running a project's build to discover its dependencies is itself
a supply chain risk. CI scans this repository with the tool on every run.
diff --git a/website/docs/output.md b/website/docs/output.md
index 5d74316..f22f3d8 100644
--- a/website/docs/output.md
+++ b/website/docs/output.md
@@ -109,7 +109,7 @@ one as evidence that anything was checked.
| `2` | Usage error: bad flag, unknown format (Click's reserved code) | Fix the invocation |
Findings deliberately never change the exit code. A scanner that exits non-zero
-on findings gets `|| true` appended within a week, at which point genuine tool
+on findings sooner or later gets `|| true` appended, at which point genuine tool
failures go unnoticed too.
!!! note "Exit 2 is usage, exit 1 is scan failure"
@@ -134,7 +134,7 @@ jq -e '(.summary.by_severity.critical // 0) == 0' report.json > /dev/null \
## A full workflow
```yaml
-name: Supply chain
+name: Dependency scan
on:
push: { branches: [main] }
@@ -165,11 +165,11 @@ jobs:
category: icebergsca
```
-The scheduled run matters more than it looks: most new findings arrive because
-an advisory was published, not because the code changed.
+The scheduled run matters: most new findings arrive because an advisory was
+published, not because the code changed.
Deliberately vulnerable test fixtures are a common source of noise — exclude
-them, rather than explaining them away every week.
+them rather than explaining them away.
### Caching between runs
diff --git a/website/zensical.toml b/website/zensical.toml
index f4128fc..95ccda1 100644
--- a/website/zensical.toml
+++ b/website/zensical.toml
@@ -3,7 +3,7 @@
[project]
site_name = "IcebergSCA"
-site_description = "Supply chain analysis for software projects: lockfile-first dependency scanning against OSV, with a report that never implies a clean result it did not earn."
+site_description = "Software composition analysis for software projects: lockfile-first dependency scanning against OSV, with a report that never implies a clean result it did not earn."
site_author = "IcebergAI"
site_url = "https://icebergai.github.io/IcebergSCA/"
@@ -122,8 +122,9 @@ check_paths = true
# sites, but no page currently uses one — the theme lazy-loads mermaid.min.js
# from **unpkg.com**, and every other asset on this site is self-hosted. Adding
# a ```mermaid fence silently reintroduces a third-party CDN dependency at view
-# time; render the diagram as a table or an inline SVG instead. On a site for a
-# supply chain scanner that would be a particularly poor look.
+# time; render the diagram as a table or an inline SVG instead. On the site for
+# a tool that exists to find undeclared third-party code, that would be a
+# particularly poor look.
custom_fences = [
{ name = "mermaid", class = "mermaid", format = "pymdownx.superfences.fence_code_format" }
]