mirror of
https://github.com/anchore/syft.git
synced 2026-10-26 03:52:22 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9673f867e5 | ||
|
|
a4fb2c0396 | ||
|
|
cf2ce643c3 | ||
|
|
524a44b70d | ||
|
|
4e86715c1a | ||
|
|
e8c6b7151e | ||
|
|
0fb8762f41 | ||
|
|
58ddf74140 | ||
|
|
b5d828ee14 | ||
|
|
1c4394fed0 | ||
|
|
f5c1a0befc | ||
|
|
b1287d45d8 | ||
|
|
d97216ff70 | ||
|
|
c09a009bda | ||
|
|
d61af0abab | ||
|
|
89cda82263 | ||
|
|
ee6ace36d1 | ||
|
|
e2e5e223ab | ||
|
|
4579d11abc | ||
|
|
07ae2ca08d | ||
|
|
36969bdeff | ||
|
|
dfb6011083 | ||
|
|
997a486e22 | ||
|
|
4f64fbc004 | ||
|
|
87d6a288d7 | ||
|
|
20987d30d0 | ||
|
|
e2007d9bf2 | ||
|
|
4f0e32ab51 | ||
|
|
605391114c | ||
|
|
1caf243d29 | ||
|
|
48e91312e8 | ||
|
|
d81df67493 | ||
|
|
47cda2b5ef | ||
|
|
ae711963d1 | ||
|
|
f878197150 | ||
|
|
514efb03e0 | ||
|
|
1e4f424f09 | ||
|
|
b5f0877967 | ||
|
|
8cb78ce40c | ||
|
|
3b046b3787 | ||
|
|
05cc8ee5f4 | ||
|
|
3562dab445 | ||
|
|
014a4c9c59 | ||
|
|
3cb838eacf | ||
|
|
758324b3e8 | ||
|
|
390cf6cce0 | ||
|
|
4393654d03 | ||
|
|
d179724f42 | ||
|
|
2ddaaac706 | ||
|
|
073b4c5d55 | ||
|
|
ff6c34de7e | ||
|
|
66ba575ae2 | ||
|
|
ed306c2a6d | ||
|
|
33bc4b8397 | ||
|
|
89e4e609d5 | ||
|
|
076fb211cc | ||
|
|
26175d74f8 | ||
|
|
9b58efed0c | ||
|
|
30fe53e629 | ||
|
|
952469f0f0 | ||
|
|
4321ecc66f | ||
|
|
5b58ec96b7 | ||
|
|
26e87c7cd3 | ||
|
|
722e3f267b | ||
|
|
c09f42e024 | ||
|
|
19b4f41270 | ||
|
|
bcc1f15ceb | ||
|
|
ce2c56bf06 | ||
|
|
532fbafe36 | ||
|
|
8835af66b0 | ||
|
|
f4290cb876 | ||
|
|
990cc3c599 | ||
|
|
03d6399b0c | ||
|
|
1e08f703d0 | ||
|
|
e420322494 | ||
|
|
cc3b8eb48f | ||
|
|
d0ee9098cf | ||
|
|
344d1f47a1 | ||
|
|
f618917527 | ||
|
|
99158be0ba | ||
|
|
2089d086fe | ||
|
|
b0dc65a4fb | ||
|
|
611a24fcae | ||
|
|
da601363ed | ||
|
|
0d748ec700 | ||
|
|
d60e43f822 | ||
|
|
2884cc77fc | ||
|
|
c11a79ef19 | ||
|
|
90198da04d | ||
|
|
d71b747cd1 | ||
|
|
58a8a95e26 | ||
|
|
78a21b9c88 | ||
|
|
7d3882a425 | ||
|
|
673c85754c | ||
|
|
c5114fd745 | ||
|
|
f68a7cc899 | ||
|
|
7800b16529 | ||
|
|
834ddcb1c0 | ||
|
|
f5d318d934 | ||
|
|
8531e1917b | ||
|
|
860126c650 | ||
|
|
36639f136b | ||
|
|
f32238c268 | ||
|
|
0c8eef65f0 | ||
|
|
4d42f8af32 | ||
|
|
e38851143e | ||
|
|
a3dacf5ecd | ||
|
|
cccc9bf7f9 | ||
|
|
59f7725d0d | ||
|
|
7a6b1575ae | ||
|
|
92a6b36e89 | ||
|
|
7158535fe6 | ||
|
|
75455f050a | ||
|
|
22e78c7be1 | ||
|
|
d2461a9e0a | ||
|
|
01f0e332c2 | ||
|
|
c88051d74e | ||
|
|
7d3d1c6237 | ||
|
|
dcba765d86 | ||
|
|
2c201469c3 | ||
|
|
c583da1c15 | ||
|
|
22014b6022 | ||
|
|
b5e85c3ea5 | ||
|
|
35278f3d3d | ||
|
|
db76d85d51 | ||
|
|
e9e7e20cc8 | ||
|
|
eb072deb9c | ||
|
|
f4fc2d669a | ||
|
|
f5110f109a | ||
|
|
612eadb22e |
+10
-99
@@ -1,52 +1,11 @@
|
||||
# only pull in version updates that were released more than a week ago (low-pass filter for quickly-retracted releases)
|
||||
cooldown: 7d
|
||||
|
||||
# Most tools (binny, chronicle, cosign, golangci-lint, goreleaser, gosimports,
|
||||
# bouncer, quill, syft, task, gh) are inherited from anchore/go-make's embedded
|
||||
# .binny.yaml — see https://github.com/anchore/go-make. Only syft-specific tools
|
||||
# or version overrides should live here.
|
||||
tools:
|
||||
# we want to use a pinned version of binny to manage the toolchain (so binny manages itself!)
|
||||
- name: binny
|
||||
version:
|
||||
want: v0.11.3
|
||||
method: github-release
|
||||
with:
|
||||
repo: anchore/binny
|
||||
|
||||
# used to produce SBOMs during release
|
||||
- name: syft
|
||||
version:
|
||||
want: latest
|
||||
method: github-release
|
||||
with:
|
||||
repo: anchore/syft
|
||||
|
||||
# used to sign mac binaries at release
|
||||
- name: quill
|
||||
version:
|
||||
want: v0.5.1
|
||||
method: github-release
|
||||
with:
|
||||
repo: anchore/quill
|
||||
|
||||
# used for linting
|
||||
- name: golangci-lint
|
||||
version:
|
||||
want: v2.9.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: golangci/golangci-lint
|
||||
|
||||
# used for showing the changelog at release
|
||||
- name: glow
|
||||
version:
|
||||
want: v2.1.1
|
||||
method: github-release
|
||||
with:
|
||||
repo: charmbracelet/glow
|
||||
|
||||
# used for signing the checksums file at release
|
||||
- name: cosign
|
||||
version:
|
||||
want: v3.0.4
|
||||
method: github-release
|
||||
with:
|
||||
repo: sigstore/cosign
|
||||
|
||||
# used in integration tests to verify JSON schemas
|
||||
- name: yajsv
|
||||
version:
|
||||
@@ -55,66 +14,18 @@ tools:
|
||||
with:
|
||||
repo: neilpa/yajsv
|
||||
|
||||
# used to release all artifacts
|
||||
- name: goreleaser
|
||||
version:
|
||||
want: v2.13.3
|
||||
method: github-release
|
||||
with:
|
||||
repo: goreleaser/goreleaser
|
||||
|
||||
# used for organizing imports during static analysis
|
||||
- name: gosimports
|
||||
version:
|
||||
want: v0.3.8
|
||||
method: github-release
|
||||
with:
|
||||
repo: rinchsan/gosimports
|
||||
|
||||
# used at release to generate the changelog
|
||||
- name: chronicle
|
||||
version:
|
||||
want: v0.8.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: anchore/chronicle
|
||||
|
||||
# used during static analysis for license compliance
|
||||
- name: bouncer
|
||||
version:
|
||||
want: v0.4.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: wagoodman/go-bouncer
|
||||
|
||||
# used for running all local and CI tasks
|
||||
- name: task
|
||||
version:
|
||||
want: v3.48.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: go-task/task
|
||||
|
||||
# used for triggering a release
|
||||
- name: gh
|
||||
version:
|
||||
want: v2.86.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: cli/cli
|
||||
|
||||
# used to upload test fixture cache
|
||||
- name: oras
|
||||
version:
|
||||
want: v1.3.0
|
||||
want: v1.3.1
|
||||
method: github-release
|
||||
with:
|
||||
repo: oras-project/oras
|
||||
|
||||
# used to upload test fixture cache
|
||||
# used to parse JSON/YAML annotations on the fixture cache image
|
||||
- name: yq
|
||||
version:
|
||||
want: v4.52.4
|
||||
want: v4.52.5
|
||||
method: github-release
|
||||
with:
|
||||
repo: mikefarah/yq
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
name: "Bootstrap"
|
||||
description: "Bootstrap all syft tools and dependencies on top of go-make's setup action"
|
||||
|
||||
# This action is a thin wrapper around anchore/go-make/.github/actions/setup which
|
||||
# already handles checkout, setup-go, restore-only build/mod cache, and tool cache.
|
||||
# We add the syft-specific extras here: apt packages and the test fixture cache.
|
||||
|
||||
description: "Bootstrap all tools and dependencies"
|
||||
inputs:
|
||||
go-version:
|
||||
description: "Go version to install"
|
||||
description: "Go version to install (passed to go-make/setup)"
|
||||
required: true
|
||||
default: "1.25.x"
|
||||
go-dependencies:
|
||||
description: "Download go dependencies"
|
||||
default: "1.26.2"
|
||||
cache-key-prefix:
|
||||
description: "Prefix all cache keys with this value (passed to go-make/setup)"
|
||||
required: true
|
||||
default: "v1"
|
||||
cache-enabled:
|
||||
description: "Enable build/mod and tool caching (passed to go-make/setup)"
|
||||
required: true
|
||||
default: "true"
|
||||
cache-key-prefix:
|
||||
description: "Prefix all cache keys with this value"
|
||||
required: true
|
||||
default: "53ac821810"
|
||||
download-test-fixture-cache:
|
||||
description: "Download test fixture cache from OCI and github actions"
|
||||
required: true
|
||||
default: "false"
|
||||
tools:
|
||||
description: "whether to install tools"
|
||||
default: "true"
|
||||
bootstrap-apt-packages:
|
||||
description: "Space delimited list of tools to install via apt"
|
||||
default: "libxml2-utils"
|
||||
@@ -28,33 +29,16 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# note: go mod and build is automatically cached on default with v4+
|
||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
||||
if: inputs.go-version != ''
|
||||
- name: Setup go + go-make tooling
|
||||
uses: anchore/go-make/.github/actions/setup@9de27be11ed73e2f9d5406a836a492b7d8aa1225 # v0.5.0
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
check-latest: true
|
||||
cache-key-prefix: ${{ inputs.cache-key-prefix }}
|
||||
cache-enabled: ${{ inputs.cache-enabled }}
|
||||
|
||||
- name: Restore tool cache
|
||||
if: inputs.tools == 'true'
|
||||
id: tool-cache
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
with:
|
||||
path: ${{ github.workspace }}/.tool
|
||||
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('.binny.yaml') }}
|
||||
|
||||
- name: Install project tools
|
||||
- name: Install binny-managed tools
|
||||
shell: bash
|
||||
if: inputs.tools == 'true'
|
||||
run: |
|
||||
make tools
|
||||
.tool/binny list
|
||||
.tool/binny check
|
||||
|
||||
- name: Install go dependencies
|
||||
if: inputs.go-dependencies == 'true'
|
||||
shell: bash
|
||||
run: make ci-bootstrap-go
|
||||
run: make binny:install
|
||||
|
||||
- name: Install apt packages
|
||||
if: inputs.bootstrap-apt-packages != ''
|
||||
@@ -65,9 +49,18 @@ runs:
|
||||
IFS=' ' read -ra packages <<< "$APT_PACKAGES"
|
||||
DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y "${packages[@]}"
|
||||
|
||||
# ORAS cache: restore-only on non-default branches / forks
|
||||
- name: Restore ORAS cache from github actions
|
||||
if: inputs.download-test-fixture-cache == 'true'
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
if: ${{ inputs.download-test-fixture-cache == 'true' && (github.ref != format('refs/heads/{0}', github.event.repository.default_branch) || github.event.repository.fork == true) }}
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: ${{ github.workspace }}/.tmp/oras-cache
|
||||
key: ${{ inputs.cache-key-prefix }}-oras-cache
|
||||
|
||||
# ORAS cache: restore + save on the default branch of the canonical repo only.
|
||||
- name: Restore and save ORAS cache from github actions
|
||||
if: ${{ inputs.download-test-fixture-cache == 'true' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.event.repository.fork == false }}
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: ${{ github.workspace }}/.tmp/oras-cache
|
||||
key: ${{ inputs.cache-key-prefix }}-oras-cache
|
||||
|
||||
@@ -14,7 +14,9 @@ version: 2
|
||||
updates:
|
||||
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
directories:
|
||||
- "/"
|
||||
- "/.make"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
schedule:
|
||||
@@ -23,6 +25,11 @@ updates:
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependencies"
|
||||
ignore:
|
||||
- dependency-name: "github.com/aquasecurity/go-pep440-version"
|
||||
- dependency-name: "github.com/aquasecurity/go-version"
|
||||
- dependency-name: "github.com/knqyf263/go-apk-version"
|
||||
- dependency-name: "github.com/knqyf263/go-deb-version"
|
||||
groups:
|
||||
go-minor-patch:
|
||||
applies-to: version-updates # security updates get individual PRs
|
||||
@@ -35,7 +42,7 @@ updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directories:
|
||||
- "/"
|
||||
- "/.github/actions/bootstrap"
|
||||
- "/.github/actions/*"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
schedule:
|
||||
|
||||
@@ -6,7 +6,7 @@ if [ "$(git status --porcelain | wc -l)" -ne "0" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! make generate-capabilities; then
|
||||
if ! make generate-capabilities REFRESH=false; then
|
||||
echo "Generating capability descriptions failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
red=$(tput setaf 1)
|
||||
bold=$(tput bold)
|
||||
normal=$(tput sgr0)
|
||||
|
||||
# assert we are running in CI (or die!)
|
||||
if [[ -z "$CI" ]]; then
|
||||
echo "${bold}${red}This step should ONLY be run in CI. Exiting...${normal}"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import subprocess
|
||||
import sys
|
||||
import shlex
|
||||
|
||||
|
||||
class bcolors:
|
||||
HEADER = '\033[95m'
|
||||
OKBLUE = '\033[94m'
|
||||
OKCYAN = '\033[96m'
|
||||
OKGREEN = '\033[92m'
|
||||
WARNING = '\033[93m'
|
||||
FAIL = '\033[91m'
|
||||
ENDC = '\033[0m'
|
||||
BOLD = '\033[1m'
|
||||
UNDERLINE = '\033[4m'
|
||||
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: coverage.py [threshold] [go-coverage-report]")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
threshold = float(sys.argv[1])
|
||||
report = sys.argv[2]
|
||||
|
||||
|
||||
args = shlex.split(f"go tool cover -func {report}")
|
||||
p = subprocess.run(args, capture_output=True, text=True)
|
||||
|
||||
percent_coverage = float(p.stdout.splitlines()[-1].split()[-1].replace("%", ""))
|
||||
print(f"{bcolors.BOLD}Coverage: {percent_coverage}%{bcolors.ENDC}")
|
||||
|
||||
if percent_coverage < threshold:
|
||||
print(f"{bcolors.BOLD}{bcolors.FAIL}Coverage below threshold of {threshold}%{bcolors.ENDC}")
|
||||
sys.exit(1)
|
||||
@@ -1,35 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import glob
|
||||
import sys
|
||||
import json
|
||||
import hashlib
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
IGNORED_PREFIXES = []
|
||||
|
||||
|
||||
def find_fingerprints_and_check_dirs(base_dir):
|
||||
all_fingerprints = set(glob.glob(os.path.join(base_dir, '**', 'test*', '**', '*.fingerprint'), recursive=True))
|
||||
all_fingerprints = set(
|
||||
glob.glob(
|
||||
os.path.join(base_dir, "**", "test*", "**", "*.fingerprint"), recursive=True
|
||||
)
|
||||
)
|
||||
|
||||
all_fingerprints = {os.path.relpath(fp) for fp in all_fingerprints
|
||||
if not any(fp.startswith(prefix) for prefix in IGNORED_PREFIXES)}
|
||||
all_fingerprints = {
|
||||
os.path.relpath(fp)
|
||||
for fp in all_fingerprints
|
||||
if not any(fp.startswith(prefix) for prefix in IGNORED_PREFIXES)
|
||||
}
|
||||
|
||||
if not all_fingerprints:
|
||||
show("No .fingerprint files or cache directories found.")
|
||||
exit(1)
|
||||
|
||||
missing_content = []
|
||||
orphan_fingerprints = []
|
||||
empty_content = []
|
||||
valid_paths = set()
|
||||
fingerprint_contents = []
|
||||
|
||||
for fingerprint in all_fingerprints:
|
||||
path = fingerprint.replace('.fingerprint', '')
|
||||
path = fingerprint.replace(".fingerprint", "")
|
||||
|
||||
if not os.path.exists(path):
|
||||
missing_content.append(path)
|
||||
# paired content path is entirely missing — the .fingerprint is likely
|
||||
# leftover from a moved/deleted source (testdata trees are git-ignored,
|
||||
# so they persist locally across rename refactors)
|
||||
orphan_fingerprints.append(fingerprint)
|
||||
continue
|
||||
|
||||
if not os.path.isdir(path):
|
||||
@@ -39,13 +49,13 @@ def find_fingerprints_and_check_dirs(base_dir):
|
||||
if os.listdir(path):
|
||||
valid_paths.add(path)
|
||||
else:
|
||||
missing_content.append(path)
|
||||
empty_content.append(path)
|
||||
|
||||
with open(fingerprint, 'r') as f:
|
||||
with open(fingerprint, "r") as f:
|
||||
content = f.read().strip()
|
||||
fingerprint_contents.append((fingerprint, content))
|
||||
|
||||
return sorted(valid_paths), missing_content, fingerprint_contents
|
||||
return sorted(valid_paths), empty_content, orphan_fingerprints, fingerprint_contents
|
||||
|
||||
|
||||
def parse_fingerprint_contents(fingerprint_content):
|
||||
@@ -59,7 +69,9 @@ def parse_fingerprint_contents(fingerprint_content):
|
||||
def calculate_sha256(fingerprint_contents):
|
||||
sorted_fingerprint_contents = sorted(fingerprint_contents, key=lambda x: x[0])
|
||||
|
||||
concatenated_contents = ''.join(content for _, content in sorted_fingerprint_contents)
|
||||
concatenated_contents = "".join(
|
||||
content for _, content in sorted_fingerprint_contents
|
||||
)
|
||||
|
||||
sha256_hash = hashlib.sha256(concatenated_contents.encode()).hexdigest()
|
||||
|
||||
@@ -68,7 +80,7 @@ def calculate_sha256(fingerprint_contents):
|
||||
|
||||
def calculate_file_sha256(file_path):
|
||||
sha256_hash = hashlib.sha256()
|
||||
with open(file_path, 'rb') as f:
|
||||
with open(file_path, "rb") as f:
|
||||
for byte_block in iter(lambda: f.read(4096), b""):
|
||||
sha256_hash.update(byte_block)
|
||||
return sha256_hash.hexdigest()
|
||||
@@ -79,17 +91,28 @@ def show(*s: str):
|
||||
|
||||
|
||||
def main(file_path: str | None):
|
||||
base_dir = '.'
|
||||
valid_paths, missing_content, fingerprint_contents = find_fingerprints_and_check_dirs(base_dir)
|
||||
base_dir = "."
|
||||
valid_paths, empty_content, orphan_fingerprints, fingerprint_contents = (
|
||||
find_fingerprints_and_check_dirs(base_dir)
|
||||
)
|
||||
|
||||
if missing_content:
|
||||
show("The following paths are missing or have no content, but have corresponding .fingerprint files:")
|
||||
for path in sorted(missing_content):
|
||||
if empty_content:
|
||||
show(
|
||||
"The following paths exist but are empty, and have corresponding .fingerprint files:"
|
||||
)
|
||||
for path in sorted(empty_content):
|
||||
show(f"- {path}")
|
||||
# when adding new cache directories there is a time where it is not possible to have this directory without
|
||||
# running the tests first... but this step is a prerequisite for running the tests. We should not block on this.
|
||||
# show("Please ensure these paths exist and have content if they are directories.")
|
||||
# exit(1)
|
||||
|
||||
if orphan_fingerprints:
|
||||
show(
|
||||
"The following .fingerprint files reference paths that no longer exist "
|
||||
"(likely leftover from a moved/deleted cataloger — safe to delete, "
|
||||
"or run `task prune-orphan-fingerprints`):"
|
||||
)
|
||||
for fp in sorted(orphan_fingerprints):
|
||||
show(f"- {fp}")
|
||||
|
||||
sha256_hash = calculate_sha256(fingerprint_contents)
|
||||
|
||||
@@ -101,30 +124,24 @@ def main(file_path: str | None):
|
||||
file_digest = calculate_file_sha256(fingerprint_file)
|
||||
|
||||
# Parse the fingerprint file to get the digest/path tuples
|
||||
with open(fingerprint_file, 'r') as f:
|
||||
with open(fingerprint_file, "r") as f:
|
||||
fingerprint_content = f.read().strip()
|
||||
input_map = parse_fingerprint_contents(fingerprint_content)
|
||||
|
||||
paths_with_digests.append({
|
||||
"path": path,
|
||||
"digest": file_digest,
|
||||
"input": input_map
|
||||
})
|
||||
paths_with_digests.append(
|
||||
{"path": path, "digest": file_digest, "input": input_map}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
show(f"Error processing {fingerprint_file}: {e}")
|
||||
raise e
|
||||
|
||||
|
||||
output = {
|
||||
"digest": sha256_hash,
|
||||
"paths": paths_with_digests
|
||||
}
|
||||
output = {"digest": sha256_hash, "paths": paths_with_digests}
|
||||
|
||||
content = json.dumps(output, indent=2, sort_keys=True)
|
||||
|
||||
if file_path:
|
||||
with open(file_path, 'w') as f:
|
||||
with open(file_path, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
print(content)
|
||||
|
||||
@@ -33,9 +33,9 @@ def is_git_tracked_or_untracked(directory):
|
||||
|
||||
|
||||
def find_test_fixture_dirs_with_images(base_dir):
|
||||
"""Find directories that contain 'test-fixtures' and at least one 'image-*' directory."""
|
||||
"""Find directories that contain 'testdata' and at least one 'image-*' directory."""
|
||||
for root, dirs, files in os.walk(base_dir):
|
||||
if 'test-fixtures' in root:
|
||||
if 'testdata' in root:
|
||||
image_dirs = [d for d in dirs if d.startswith('image-')]
|
||||
if image_dirs:
|
||||
yield os.path.realpath(root)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
ORIGINAL_STATE_DIR=$(mktemp -d "TEMP-original-state-XXXXXXXXX")
|
||||
TIDY_STATE_DIR=$(mktemp -d "TEMP-tidy-state-XXXXXXXXX")
|
||||
|
||||
trap "cp -p ${ORIGINAL_STATE_DIR}/* ./ && git update-index -q --refresh && rm -fR ${ORIGINAL_STATE_DIR} ${TIDY_STATE_DIR}" EXIT
|
||||
|
||||
# capturing original state of files...
|
||||
cp go.mod go.sum "${ORIGINAL_STATE_DIR}"
|
||||
|
||||
# capturing state of go.mod and go.sum after running go mod tidy...
|
||||
go mod tidy
|
||||
cp go.mod go.sum "${TIDY_STATE_DIR}"
|
||||
|
||||
set +e
|
||||
|
||||
# detect difference between the git HEAD state and the go mod tidy state
|
||||
DIFF_MOD=$(diff -u "${ORIGINAL_STATE_DIR}/go.mod" "${TIDY_STATE_DIR}/go.mod")
|
||||
DIFF_SUM=$(diff -u "${ORIGINAL_STATE_DIR}/go.sum" "${TIDY_STATE_DIR}/go.sum")
|
||||
|
||||
if [[ -n "${DIFF_MOD}" || -n "${DIFF_SUM}" ]]; then
|
||||
echo "go.mod diff:"
|
||||
echo "${DIFF_MOD}"
|
||||
echo "go.sum diff:"
|
||||
echo "${DIFF_SUM}"
|
||||
echo ""
|
||||
printf "FAILED! go.mod and/or go.sum are NOT tidy; please run 'go mod tidy'.\n\n"
|
||||
exit 1
|
||||
fi
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Remove orphan *.fingerprint files left behind by moved/deleted catalogers.
|
||||
|
||||
A fingerprint is considered orphaned when:
|
||||
1. its paired content path (the fingerprint path with `.fingerprint` stripped)
|
||||
does not exist, AND
|
||||
2. the nearest ancestor `testdata/` directory has no `Makefile` claiming
|
||||
responsibility for generating that path.
|
||||
|
||||
The second condition is the safety check: if there is a Makefile, the
|
||||
fingerprint is "live" and might just be waiting for fixtures to be built —
|
||||
leave it alone. Without a Makefile, nothing in-repo will ever regenerate
|
||||
the content, so the fingerprint is dead weight that triggers spurious
|
||||
"missing path" warnings.
|
||||
|
||||
Empty parent directories are also pruned after removing the fingerprint.
|
||||
|
||||
Use --dry-run to preview without deleting.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def find_ancestor_testdata(path: str) -> str | None:
|
||||
d = os.path.dirname(path)
|
||||
while d and d not in (".", os.sep):
|
||||
if os.path.basename(d) == "testdata":
|
||||
return d
|
||||
d = os.path.dirname(d)
|
||||
return None
|
||||
|
||||
|
||||
def is_orphan(fingerprint: str) -> bool:
|
||||
paired = fingerprint[: -len(".fingerprint")]
|
||||
if os.path.exists(paired):
|
||||
return False
|
||||
|
||||
testdata_dir = find_ancestor_testdata(fingerprint)
|
||||
if testdata_dir and os.path.isfile(os.path.join(testdata_dir, "Makefile")):
|
||||
# a Makefile exists that may regenerate this — not safe to prune
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def prune_empty_parents(start: str, stop_at: str = ".") -> list[str]:
|
||||
removed = []
|
||||
d = os.path.dirname(start)
|
||||
stop_at = os.path.abspath(stop_at)
|
||||
while d and os.path.abspath(d) != stop_at:
|
||||
try:
|
||||
if not os.listdir(d):
|
||||
os.rmdir(d)
|
||||
removed.append(d)
|
||||
d = os.path.dirname(d)
|
||||
else:
|
||||
break
|
||||
except OSError:
|
||||
break
|
||||
return removed
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="Show what would be removed without deleting anything",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
all_fingerprints = glob.glob("**/test*/**/*.fingerprint", recursive=True)
|
||||
orphans = sorted(fp for fp in all_fingerprints if is_orphan(fp))
|
||||
|
||||
if not orphans:
|
||||
print("no orphan fingerprints found")
|
||||
return 0
|
||||
|
||||
verb = "would remove" if args.dry_run else "removing"
|
||||
print(f"{verb} {len(orphans)} orphan fingerprint(s):")
|
||||
for fp in orphans:
|
||||
print(f"- {fp}")
|
||||
if args.dry_run:
|
||||
continue
|
||||
try:
|
||||
os.remove(fp)
|
||||
except OSError as e:
|
||||
print(f" ! failed to remove: {e}", file=sys.stderr)
|
||||
continue
|
||||
for d in prune_empty_parents(fp):
|
||||
print(f" (also removed empty dir {d})")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
bold=$(tput bold)
|
||||
normal=$(tput sgr0)
|
||||
|
||||
GH_CLI=.tool/gh
|
||||
|
||||
if ! [ -x "$(command -v $GH_CLI)" ]; then
|
||||
echo "The GitHub CLI could not be found. run: make bootstrap"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$GH_CLI auth status
|
||||
|
||||
# set the default repo in cases where multiple remotes are defined
|
||||
$GH_CLI repo set-default anchore/syft
|
||||
|
||||
export GITHUB_TOKEN="${GITHUB_TOKEN-"$($GH_CLI auth token)"}"
|
||||
|
||||
# we need all of the git state to determine the next version. Since tagging is done by
|
||||
# the release pipeline it is possible to not have all of the tags from previous releases.
|
||||
git fetch --tags
|
||||
|
||||
# populates the CHANGELOG.md and VERSION files
|
||||
echo "${bold}Generating changelog...${normal}"
|
||||
make changelog 2> /dev/null
|
||||
|
||||
NEXT_VERSION=$(cat VERSION)
|
||||
|
||||
if [[ "$NEXT_VERSION" == "" || "${NEXT_VERSION}" == "(Unreleased)" ]]; then
|
||||
echo "Could not determine the next version to release. Exiting..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while true; do
|
||||
read -p "${bold}Do you want to trigger a release for version '${NEXT_VERSION}'?${normal} [y/n] " yn
|
||||
case $yn in
|
||||
[Yy]* ) echo; break;;
|
||||
[Nn]* ) echo; echo "Cancelling release..."; exit;;
|
||||
* ) echo "Please answer yes or no.";;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "${bold}Kicking off release for ${NEXT_VERSION}${normal}..."
|
||||
echo
|
||||
$GH_CLI workflow run release.yaml -f version=${NEXT_VERSION}
|
||||
|
||||
echo
|
||||
echo "${bold}Waiting for release to start...${normal}"
|
||||
sleep 10
|
||||
|
||||
set +e
|
||||
|
||||
echo "${bold}Head to the release workflow to monitor the release:${normal} $($GH_CLI run list --workflow=release.yaml --limit=1 --json url --jq '.[].url')"
|
||||
id=$($GH_CLI run list --workflow=release.yaml --limit=1 --json databaseId --jq '.[].databaseId')
|
||||
$GH_CLI run watch $id --exit-status || (echo ; echo "${bold}Logs of failed step:${normal}" && GH_PAGER="" $GH_CLI run view $id --log-failed)
|
||||
@@ -1,76 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL Security Scan"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
# only run when there are pushes to the main branch (not on PRs)
|
||||
- main
|
||||
|
||||
schedule:
|
||||
- cron: '0 0 * * 3'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-22.04-4core-16gb
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
permissions:
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['go', 'python']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 #v6.2.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10
|
||||
@@ -0,0 +1,21 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: '38 11 * * 3'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
uses: anchore/workflows/.github/workflows/codeql.yaml@b3e328b5ae31ba96297e2ed9a6124e5e6352a4c5 # v0.7.0
|
||||
permissions:
|
||||
security-events: write
|
||||
packages: read
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -1,10 +0,0 @@
|
||||
name: Dependabot Automation
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
run:
|
||||
uses: anchore/workflows/.github/workflows/dependabot-automation.yaml@main
|
||||
@@ -1,60 +0,0 @@
|
||||
name: "Detect schema changes"
|
||||
|
||||
on:
|
||||
# IMPORTANT! This workflow is triggered by the `pull_request_target` event
|
||||
# which means that forked PRs will run with access secrets from the repo
|
||||
# it's forked from (the "target" repo).
|
||||
#
|
||||
# For this reason we only NEVER checkout the code from the pull request
|
||||
# (e.g. "ref: ${{ github.event.pull_request.head.sha }}") to prevent
|
||||
# accidentally running potentially untrusted code.
|
||||
#
|
||||
# By default the checkout will be:
|
||||
# - GITHUB_SHA: Last commit on the PR base branch
|
||||
# - GITHUB_REF: PR base branch
|
||||
#
|
||||
# ...unlike a typical PR where:
|
||||
# - GITHUB_SHA: Last merge commit on the GITHUB_REF branch
|
||||
# - GITHUB_REF: PR merge branch refs/pull/:prNumber/merge
|
||||
pull_request_target:
|
||||
|
||||
env:
|
||||
# note: this is used within hashFiles() so must be within the GITHUB_WORKSPACE path (or will silently fail)
|
||||
CI_COMMENT_FILE: .tmp/labeler-comment.txt
|
||||
# needs to be any string to uniquely identify the comment on a PR across multiple runs
|
||||
COMMENT_HEADER: "label-commentary"
|
||||
|
||||
jobs:
|
||||
label:
|
||||
name: "Label changes"
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- run: python .github/scripts/labeler.py
|
||||
env:
|
||||
# note: this token has write access to the repo
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_PR_NUMBER: ${{ github.event.number }}
|
||||
|
||||
- name: Delete existing comment
|
||||
if: ${{ hashFiles( env.CI_COMMENT_FILE ) == '' }}
|
||||
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 #v2.9.4
|
||||
with:
|
||||
header: ${{ env.COMMENT_HEADER }}
|
||||
hide: true
|
||||
hide_classify: "OUTDATED"
|
||||
|
||||
- name: Add comment
|
||||
if: ${{ hashFiles( env.CI_COMMENT_FILE ) != '' }}
|
||||
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 #v2.9.4
|
||||
with:
|
||||
header: ${{ env.COMMENT_HEADER }}
|
||||
path: ${{ env.CI_COMMENT_FILE }}
|
||||
@@ -1,18 +0,0 @@
|
||||
name: Add to OSS board
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- transferred
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
run:
|
||||
uses: "anchore/workflows/.github/workflows/oss-project-board-add.yaml@main"
|
||||
secrets:
|
||||
token: ${{ secrets.OSS_PROJECT_GH_TOKEN }}
|
||||
+38
-146
@@ -1,7 +1,11 @@
|
||||
name: "Release"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
permissions: {}
|
||||
|
||||
# there should never be two releases in progress at the same time
|
||||
concurrency:
|
||||
group: release
|
||||
cancel-in-progress: false
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -19,116 +23,30 @@ on:
|
||||
- "install-script-only"
|
||||
|
||||
jobs:
|
||||
quality-gate:
|
||||
environment: release
|
||||
version-available:
|
||||
if: ${{ github.event.inputs.phase == 'all' }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
permissions:
|
||||
contents: read # required for fetching tags
|
||||
uses: anchore/workflows/.github/workflows/check-version-available.yaml@b3e328b5ae31ba96297e2ed9a6124e5e6352a4c5 # v0.7.0
|
||||
with:
|
||||
version: ${{ github.event.inputs.version }}
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Validate Apple notarization credentials
|
||||
run: .tool/quill submission list
|
||||
env:
|
||||
QUILL_NOTARY_ISSUER: ${{ secrets.APPLE_NOTARY_ISSUER }}
|
||||
QUILL_NOTARY_KEY_ID: ${{ secrets.APPLE_NOTARY_KEY_ID }}
|
||||
QUILL_NOTARY_KEY: ${{ secrets.APPLE_NOTARY_KEY }}
|
||||
|
||||
- name: Check if running on main
|
||||
if: github.ref != 'refs/heads/main'
|
||||
# we are using the following flag when running `cosign blob-verify` for checksum signature verification:
|
||||
# --certificate-identity-regexp "https://github.com/anchore/.github/workflows/release.yaml@refs/heads/main"
|
||||
# if we are not on the main branch, the signature will not be verifiable since the suffix requires the main branch
|
||||
# at the time of when the OIDC token was issued on the Github Actions runner.
|
||||
run: echo "This can only be run on the main branch otherwise releases produced will not be verifiable with cosign" && exit 1
|
||||
|
||||
- name: Check if tag already exists
|
||||
# note: this will fail if the tag already exists
|
||||
run: |
|
||||
[[ "$VERSION" == v* ]] || (echo "version '$VERSION' does not have a 'v' prefix" && exit 1)
|
||||
git tag "$VERSION"
|
||||
env:
|
||||
VERSION: ${{ github.event.inputs.version }}
|
||||
|
||||
- name: Check static analysis results
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
id: static-analysis
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
|
||||
checkName: "Static analysis"
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check unit test results
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
id: unit
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
|
||||
checkName: "Unit tests"
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check integration test results
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
id: integration
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
|
||||
checkName: "Integration tests"
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check acceptance test results (linux)
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
id: acceptance-linux
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
|
||||
checkName: "Acceptance tests (Linux)"
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check acceptance test results (mac)
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
id: acceptance-mac
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
|
||||
checkName: "Acceptance tests (Mac)"
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Check cli test results (linux)
|
||||
uses: fountainhead/action-wait-for-check@5a908a24814494009c4bb27c242ea38c93c593be # v1.2.0
|
||||
id: cli-linux
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
|
||||
checkName: "CLI tests (Linux)"
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Quality gate
|
||||
if: steps.static-analysis.outputs.conclusion != 'success' || steps.unit.outputs.conclusion != 'success' || steps.integration.outputs.conclusion != 'success' || steps.cli-linux.outputs.conclusion != 'success' || steps.acceptance-linux.outputs.conclusion != 'success' || steps.acceptance-mac.outputs.conclusion != 'success'
|
||||
env:
|
||||
STATIC_ANALYSIS_STATUS: ${{ steps.static-analysis.conclusion }}
|
||||
UNIT_TEST_STATUS: ${{ steps.unit.outputs.conclusion }}
|
||||
INTEGRATION_TEST_STATUS: ${{ steps.integration.outputs.conclusion }}
|
||||
ACCEPTANCE_LINUX_STATUS: ${{ steps.acceptance-linux.outputs.conclusion }}
|
||||
ACCEPTANCE_MAC_STATUS: ${{ steps.acceptance-mac.outputs.conclusion }}
|
||||
CLI_LINUX_STATUS: ${{ steps.cli-linux.outputs.conclusion }}
|
||||
run: |
|
||||
echo "Static Analysis Status: $STATIC_ANALYSIS_STATUS"
|
||||
echo "Unit Test Status: $UNIT_TEST_STATUS"
|
||||
echo "Integration Test Status: $INTEGRATION_TEST_STATUS"
|
||||
echo "Acceptance Test (Linux) Status: $ACCEPTANCE_LINUX_STATUS"
|
||||
echo "Acceptance Test (Mac) Status: $ACCEPTANCE_MAC_STATUS"
|
||||
echo "CLI Test (Linux) Status: $CLI_LINUX_STATUS"
|
||||
false
|
||||
check-gate:
|
||||
if: ${{ github.event.inputs.phase == 'all' }}
|
||||
permissions:
|
||||
contents: read
|
||||
checks: read # required for getting the status of specific check names
|
||||
uses: anchore/workflows/.github/workflows/check-gate.yaml@b3e328b5ae31ba96297e2ed9a6124e5e6352a4c5 # v0.7.0
|
||||
with:
|
||||
# these are checks that should be run on pull-request and merges to main.
|
||||
# we do NOT want to kick off a release if these have not been verified on main.
|
||||
# Please see the validations.yaml workflow for the names that should be used here.
|
||||
checks: '["Acceptance tests (Linux)", "Acceptance tests (Mac)", "Build snapshot artifacts", "CLI tests (Linux)", "Integration tests", "Static analysis", "Unit tests"]'
|
||||
|
||||
release:
|
||||
needs: [ quality-gate ]
|
||||
needs: [check-gate, version-available]
|
||||
if: ${{ github.event.inputs.phase == 'all' }}
|
||||
environment: release
|
||||
# runs-on.com: compute instances for parallel builds
|
||||
# spot disabled: reliability for build workflows (used for releases too)
|
||||
# goreleaser uses parallelism of 12, so we need more CPUs
|
||||
@@ -136,10 +54,9 @@ jobs:
|
||||
# tmpfs: faster io-intensive workflows
|
||||
runs-on: runs-on=${{ github.run_id }}/cpu=16+32/ram=32+128/family=c5+c6+c7+c8/spot=false/extras=s3-cache+tmpfs
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
# required for goreleaser signs section with cosign
|
||||
id-token: write
|
||||
contents: write # required for creating the GitHub release and pushing the version tag
|
||||
packages: write # required for publishing release artifacts to GitHub packages
|
||||
id-token: write # required for keyless signing (cosign/sigstore OIDC)
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
@@ -150,31 +67,24 @@ jobs:
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 #v3.7.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee #v4.2.0
|
||||
with:
|
||||
username: ${{ secrets.ANCHOREOSSWRITE_DH_USERNAME }}
|
||||
password: ${{ secrets.ANCHOREOSSWRITE_DH_PAT }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 #v3.7.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee #v4.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Tag release
|
||||
run: |
|
||||
git config --global user.name "anchoreci"
|
||||
git config --global user.email "anchoreci@users.noreply.github.com"
|
||||
git tag -a "$VERSION" -m "Release $VERSION"
|
||||
git push origin --tags
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION: ${{ github.event.inputs.version }}
|
||||
|
||||
- name: Build & publish release artifacts
|
||||
run: make ci-release
|
||||
env:
|
||||
# used for pushing tags
|
||||
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
||||
RELEASE_VERSION: ${{ github.event.inputs.version }}
|
||||
# for mac signing and notarization...
|
||||
QUILL_SIGN_P12: ${{ secrets.ANCHORE_APPLE_DEVELOPER_ID_CERT_CHAIN }}
|
||||
QUILL_SIGN_PASSWORD: ${{ secrets.ANCHORE_APPLE_DEVELOPER_ID_CERT_PASS }}
|
||||
@@ -186,36 +96,18 @@ jobs:
|
||||
# for updating brew formula in anchore/homebrew-syft
|
||||
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
|
||||
|
||||
- uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad #v0.22.2
|
||||
- uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 #v0.24.0
|
||||
continue-on-error: true
|
||||
with:
|
||||
file: go.mod
|
||||
artifact-name: sbom.spdx.json
|
||||
|
||||
- name: Notify Slack of new release
|
||||
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a #v2.1.1
|
||||
continue-on-error: true
|
||||
with:
|
||||
webhook: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
|
||||
webhook-type: incoming-webhook
|
||||
payload: |
|
||||
text: "A new Syft release has been published: https://github.com/anchore/syft/releases/tag/${{ github.event.inputs.version }}"
|
||||
blocks:
|
||||
- type: section
|
||||
text:
|
||||
type: mrkdwn
|
||||
text: |
|
||||
*A new Syft release has been published* :rocket:
|
||||
• Release: <https://github.com/anchore/syft/releases/tag/${{ github.event.inputs.version }}|${{ github.event.inputs.version }}>
|
||||
• Repo: `${{ github.repository }}`
|
||||
• Workflow: `${{ github.workflow }}`
|
||||
• Event: `${{ github.event_name }}`
|
||||
if: ${{ success() }}
|
||||
|
||||
release-install-script:
|
||||
needs: [ release ]
|
||||
needs: [release]
|
||||
if: ${{ always() && (needs.release.result == 'success' || github.event.inputs.phase == 'install-script-only') }}
|
||||
uses: "anchore/workflows/.github/workflows/release-install-script.yaml@main"
|
||||
permissions:
|
||||
contents: read # required for the reusable workflow to check out the repo and publish the install script
|
||||
uses: anchore/workflows/.github/workflows/release-install-script.yaml@b3e328b5ae31ba96297e2ed9a6124e5e6352a4c5 # v0.7.0
|
||||
with:
|
||||
tag: ${{ github.event.inputs.version }}
|
||||
secrets:
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
name: "Manage Awaiting Response Label"
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
run:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
uses: "anchore/workflows/.github/workflows/remove-awaiting-response-label.yaml@main"
|
||||
secrets:
|
||||
token: ${{ secrets.OSS_PROJECT_GH_TOKEN }}
|
||||
@@ -1,48 +0,0 @@
|
||||
name: "Test fixture cache: publish"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# run nightly at 4AM UTC
|
||||
- cron: "0 4 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
|
||||
Publish:
|
||||
name: "Publish test fixture image cache"
|
||||
# runs-on.com: general purpose instances for building test fixture cache
|
||||
# spot disabled: can run up to an hour, avoid interruptions
|
||||
# s3-cache: faster actions cache
|
||||
# family: note that m*d instances have local nvme storage which is beneficial for building large test fixture images
|
||||
runs-on: "runs-on=${{ github.run_id }}/cpu=8+16/ram=32+64/family=m5d+m5ad+m5dn+m6gd+m6id+m6idn+m7gd+m8gd/spot=false/extras=s3-cache"
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
with:
|
||||
# we want to rebuild the cache with no previous state
|
||||
download-test-fixture-cache: false
|
||||
|
||||
- name: Run all tests
|
||||
run: |
|
||||
make test
|
||||
env:
|
||||
# we want to rebuild the cache with no previous state
|
||||
DOWNLOAD_TEST_FIXTURE_CACHE: "false"
|
||||
|
||||
- name: Login to GitHub Container Registry (ORAS)
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | .tool/oras login ghcr.io -u "$ACTOR" --password-stdin
|
||||
env:
|
||||
ACTOR: ${{ github.actor }}
|
||||
|
||||
- name: Publish test fixture cache
|
||||
run: make upload-test-fixture-cache
|
||||
@@ -1,51 +0,0 @@
|
||||
name: PR to update Anchore dependencies
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
repos:
|
||||
description: "List of dependencies to update"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'anchore' # only run for main repo (not forks)
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
with:
|
||||
tools: false
|
||||
bootstrap-apt-packages: ""
|
||||
|
||||
- name: Update dependencies
|
||||
id: update
|
||||
uses: anchore/workflows/.github/actions/update-go-dependencies@main
|
||||
with:
|
||||
repos: ${{ github.event.inputs.repos }}
|
||||
|
||||
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf #v2.2.1
|
||||
id: generate-token
|
||||
with:
|
||||
app-id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private-key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 #v8.1.0
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
draft: ${{ steps.update.outputs.draft }}
|
||||
# do not change this branch, as other workflows depend on it
|
||||
branch: auto/integration
|
||||
labels: dependencies,pre-release
|
||||
commit-message: "chore(deps): update anchore dependencies"
|
||||
title: "chore(deps): update anchore dependencies"
|
||||
body: ${{ steps.update.outputs.summary }}
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
@@ -1,67 +0,0 @@
|
||||
name: PR for latest versions of tools
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 8 * * *" # 3 AM EST
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update-bootstrap-tools:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
with:
|
||||
bootstrap-apt-packages: ""
|
||||
go-dependencies: false
|
||||
|
||||
- name: "Update tool versions"
|
||||
id: latest-versions
|
||||
run: |
|
||||
make update-tools
|
||||
make list-tools
|
||||
|
||||
export NO_COLOR=1
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
|
||||
{
|
||||
echo "status<<${delimiter}"
|
||||
make list-tool-updates
|
||||
echo "${delimiter}"
|
||||
} >> $GITHUB_OUTPUT
|
||||
|
||||
{
|
||||
echo "### Tool version status"
|
||||
echo "\`\`\`"
|
||||
make list-tool-updates
|
||||
echo "\`\`\`"
|
||||
} >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf #v2.2.1
|
||||
id: generate-token
|
||||
with:
|
||||
app-id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private-key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 #v8.1.0
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
branch: auto/latest-tools
|
||||
labels: dependencies
|
||||
commit-message: 'chore(deps): update tools to latest versions'
|
||||
title: 'chore(deps): update tools to latest versions'
|
||||
body: |
|
||||
```
|
||||
${{ steps.latest-versions.outputs.status }}
|
||||
```
|
||||
This is an auto-generated pull request to update all of the tools to the latest versions.
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
@@ -1,84 +0,0 @@
|
||||
name: PR to update CPE dictionary index
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 1 * * 1" # every monday at 1 AM
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
SLACK_NOTIFICATIONS: true
|
||||
|
||||
jobs:
|
||||
upgrade-cpe-dictionary-index:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
id: bootstrap
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | .tool/oras login ghcr.io -u "$ACTOR" --password-stdin
|
||||
env:
|
||||
ACTOR: ${{ github.actor }}
|
||||
|
||||
- name: Pull CPE cache from registry
|
||||
run: make generate:cpe-index:cache:pull
|
||||
|
||||
- name: Update CPE cache from NVD API
|
||||
run: make generate:cpe-index:cache:update
|
||||
env:
|
||||
NVD_API_KEY: ${{ secrets.NVD_API_KEY }}
|
||||
|
||||
- name: Generate CPE dictionary index
|
||||
run: make generate:cpe-index:build
|
||||
|
||||
- name: Push updated CPE cache to registry
|
||||
run: make generate:cpe-index:cache:push
|
||||
|
||||
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf #v2.2.1
|
||||
id: generate-token
|
||||
with:
|
||||
app-id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private-key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 #v8.1.0
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
branch: auto/latest-cpe-dictionary-index
|
||||
labels: dependencies
|
||||
commit-message: "chore(deps): update CPE dictionary index"
|
||||
title: "chore(deps): update CPE dictionary index"
|
||||
body: |
|
||||
Update CPE dictionary index based on the latest available CPE dictionary
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
- name: Notify Slack on failure
|
||||
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a #v2.1.1
|
||||
with:
|
||||
webhook: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
|
||||
webhook-type: incoming-webhook
|
||||
payload: |
|
||||
text: "Syft CPE dictionary index update failed"
|
||||
blocks:
|
||||
- type: section
|
||||
text:
|
||||
type: mrkdwn
|
||||
text: |
|
||||
*Syft CPE dictionary index update failed*
|
||||
• Workflow: `${{ github.workflow }}`
|
||||
• Event: `${{ github.event_name }}`
|
||||
• Job Status: `${{ job.status }}`
|
||||
• <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>
|
||||
if: ${{ failure() && env.SLACK_NOTIFICATIONS == 'true' }}
|
||||
@@ -1,64 +0,0 @@
|
||||
name: PR to update SPDX license list
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 6 * * 1" # every monday at 6 AM UTC
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
SLACK_NOTIFICATIONS: true
|
||||
|
||||
jobs:
|
||||
upgrade-spdx-license-list:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'anchore/syft' # only run for main repo
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Bootstrap environment
|
||||
uses: ./.github/actions/bootstrap
|
||||
|
||||
- run: |
|
||||
make generate-license-list
|
||||
|
||||
- uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a #v2.1.0
|
||||
id: generate-token
|
||||
with:
|
||||
app_id: ${{ secrets.TOKEN_APP_ID }}
|
||||
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 #v8.1.0
|
||||
with:
|
||||
signoff: true
|
||||
delete-branch: true
|
||||
branch: auto/latest-spdx-license-list
|
||||
labels: dependencies
|
||||
commit-message: "chore(deps): update SPDX license list"
|
||||
title: "chore(deps): update SPDX license list"
|
||||
body: |
|
||||
Update SPDX license list based on the latest available list from spdx.org
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
- name: Notify Slack on failure
|
||||
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a #v2.1.1
|
||||
with:
|
||||
webhook: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
|
||||
webhook-type: incoming-webhook
|
||||
payload: |
|
||||
text: "Syft SPDX license list update failed"
|
||||
blocks:
|
||||
- type: section
|
||||
text:
|
||||
type: mrkdwn
|
||||
text: |
|
||||
*Syft SPDX license list update failed*
|
||||
• Workflow: `${{ github.workflow }}`
|
||||
• Event: `${{ github.event_name }}`
|
||||
• Job Status: `${{ job.status }}`
|
||||
• <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>
|
||||
if: ${{ failure() && env.SLACK_NOTIFICATIONS == 'true' }}
|
||||
@@ -1,10 +1,8 @@
|
||||
name: "Validate GitHub Actions"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/**'
|
||||
- '.github/actions/**'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
@@ -12,8 +10,7 @@ on:
|
||||
- '.github/workflows/**'
|
||||
- '.github/actions/**'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
zizmor:
|
||||
@@ -28,9 +25,8 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run zizmor"
|
||||
uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0
|
||||
uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
|
||||
with:
|
||||
config: .github/zizmor.yml
|
||||
# Disable SARIF upload so the step is a simple pass/fail gate
|
||||
advanced-security: false
|
||||
# there is a pass/fail gate as a repo ruleset (if there is no ruleset configured then the action will pass by default)
|
||||
advanced-security: true
|
||||
inputs: .github
|
||||
|
||||
@@ -13,8 +13,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
Static-Analysis:
|
||||
@@ -22,9 +21,12 @@ jobs:
|
||||
name: "Static analysis"
|
||||
# runs-on.com: memory & general purpose instances for testing
|
||||
# spot enabled: ok to interrupt non-production workloads
|
||||
# s3-cache: faster actions cache
|
||||
# tmpfs: faster io-intensive workflows
|
||||
runs-on: &test-runner "runs-on=${{ github.run_id }}/cpu=4+8/ram=32+128/family=r5+r6+r7+r8+m4+m5+m6+m7+m8/spot=price-capacity-optimized/extras=s3-cache+tmpfs"
|
||||
# note: s3-cache intentionally omitted -- PR runs are untrusted and must not write to the
|
||||
# shared cache backend that the trusted release workflow reads from (cache poisoning).
|
||||
runs-on: &test-runner "runs-on=${{ github.run_id }}/cpu=4+8/ram=32+128/family=r5+r6+r7+r8+m4+m5+m6+m7+m8/spot=price-capacity-optimized/extras=tmpfs"
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
@@ -45,6 +47,8 @@ jobs:
|
||||
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
|
||||
name: "Unit tests"
|
||||
runs-on: *test-runner
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
@@ -58,10 +62,15 @@ jobs:
|
||||
- name: Run unit tests
|
||||
run: make unit
|
||||
|
||||
- name: Check for capability drift
|
||||
run: make check-capability-drift
|
||||
|
||||
Integration-Test:
|
||||
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
|
||||
name: "Integration tests"
|
||||
runs-on: *test-runner
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
@@ -83,13 +92,13 @@ jobs:
|
||||
# runs-on.com: compute instances for parallel builds
|
||||
# spot disabled: reliability for build workflows (used for releases too)
|
||||
# goreleaser uses parallelism of 12, so we need more CPUs
|
||||
# s3-cache: faster actions cache
|
||||
# tmpfs: faster io-intensive workflows
|
||||
runs-on: "runs-on=${{ github.run_id }}/cpu=16+32/ram=32+128/family=c5+c6+c7+c8/spot=false/extras=s3-cache+tmpfs"
|
||||
# note: s3-cache intentionally omitted -- PR runs are untrusted and must not write to the
|
||||
# shared cache backend that the trusted release workflow reads from (cache poisoning).
|
||||
runs-on: "runs-on=${{ github.run_id }}/cpu=16+32/ram=32+128/family=c5+c6+c7+c8/spot=false/extras=tmpfs"
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
# required for magic-cache from runs-on to function with artifact upload/download (see https://runs-on.com/caching/magic-cache/#actionsupload-artifact-compatibility)
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3
|
||||
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
@@ -106,7 +115,7 @@ jobs:
|
||||
run: make snapshot-smoke-test
|
||||
|
||||
- name: Upload snapshot artifacts
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f #v6.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
|
||||
with:
|
||||
name: snapshot
|
||||
path: snapshot/
|
||||
@@ -117,10 +126,9 @@ jobs:
|
||||
name: "Acceptance tests (Linux)"
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: *test-runner
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
# required for magic-cache from runs-on to function with artifact upload/download (see https://runs-on.com/caching/magic-cache/#actionsupload-artifact-compatibility)
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3
|
||||
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
@@ -131,7 +139,7 @@ jobs:
|
||||
download-test-fixture-cache: true
|
||||
|
||||
- name: Download snapshot artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 #v7.0.0
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1
|
||||
with:
|
||||
name: snapshot
|
||||
path: snapshot
|
||||
@@ -159,9 +167,11 @@ jobs:
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
# note: macos runners aren't supported yet for runs-on managed runners.
|
||||
runs-on: macos-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
|
||||
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
||||
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
@@ -175,7 +185,7 @@ jobs:
|
||||
download-test-fixture-cache: true
|
||||
|
||||
- name: Download snapshot artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 #v7.0.0
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1
|
||||
with:
|
||||
name: snapshot
|
||||
path: snapshot
|
||||
@@ -194,10 +204,9 @@ jobs:
|
||||
name: "CLI tests (Linux)"
|
||||
needs: [Build-Snapshot-Artifacts]
|
||||
runs-on: *test-runner
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
# required for magic-cache from runs-on to function with artifact upload/download (see https://runs-on.com/caching/magic-cache/#actionsupload-artifact-compatibility)
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # v2.0.3
|
||||
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
@@ -208,7 +217,7 @@ jobs:
|
||||
download-test-fixture-cache: true
|
||||
|
||||
- name: Download snapshot artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 #v7.0.0
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1
|
||||
with:
|
||||
name: snapshot
|
||||
path: snapshot
|
||||
|
||||
+5
-2
@@ -3,6 +3,8 @@ go.work
|
||||
go.work.sum
|
||||
.tool-versions
|
||||
.python-version
|
||||
.mise.toml
|
||||
.env
|
||||
|
||||
# app configuration
|
||||
/.syft.yaml
|
||||
@@ -20,6 +22,8 @@ bin/
|
||||
/generate
|
||||
/specs
|
||||
mise.toml
|
||||
.make/.make
|
||||
.conductor
|
||||
|
||||
# changelog generation
|
||||
CHANGELOG.md
|
||||
@@ -37,6 +41,7 @@ VERSION
|
||||
coverage.txt
|
||||
*.log
|
||||
**/test-fixtures/test-observations.json
|
||||
**/testdata/test-observations.json
|
||||
|
||||
# probable archives
|
||||
.images
|
||||
@@ -75,5 +80,3 @@ cosign.pub
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
|
||||
|
||||
+55
-1
@@ -14,7 +14,7 @@ builds:
|
||||
dir: ./cmd/syft
|
||||
binary: syft
|
||||
goos: [linux]
|
||||
goarch: [amd64, arm64, ppc64le, s390x]
|
||||
goarch: [amd64, arm64, ppc64le, riscv64, s390x]
|
||||
mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}'
|
||||
ldflags: &build-ldflags |
|
||||
-w
|
||||
@@ -114,6 +114,20 @@ dockers:
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-riscv64
|
||||
goarch: riscv64
|
||||
dockerfile: Dockerfile
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/riscv64"
|
||||
- "--build-arg=DEBIAN_VERSION=13"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-s390x
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-s390x
|
||||
@@ -167,6 +181,20 @@ dockers:
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-nonroot-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-riscv64
|
||||
goarch: riscv64
|
||||
dockerfile: Dockerfile.nonroot
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/riscv64"
|
||||
- "--build-arg=DEBIAN_VERSION=13"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-nonroot-s390x
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
|
||||
@@ -220,6 +248,20 @@ dockers:
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-debug-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-riscv64
|
||||
goarch: riscv64
|
||||
dockerfile: Dockerfile.debug
|
||||
use: buildx
|
||||
build_flag_templates:
|
||||
- "--platform=linux/riscv64"
|
||||
- "--build-arg=DEBIAN_VERSION=13"
|
||||
- "--build-arg=BUILD_DATE={{.Date}}"
|
||||
- "--build-arg=BUILD_VERSION={{.Version}}"
|
||||
- "--build-arg=VCS_REF={{.FullCommit}}"
|
||||
- "--build-arg=VCS_URL={{.GitURL}}"
|
||||
|
||||
- image_templates:
|
||||
- anchore/syft:{{.Tag}}-debug-s390x
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
|
||||
@@ -239,6 +281,7 @@ docker_manifests:
|
||||
- anchore/syft:{{.Tag}}-amd64
|
||||
- anchore/syft:{{.Tag}}-arm64v8
|
||||
- anchore/syft:{{.Tag}}-ppc64le
|
||||
- anchore/syft:{{.Tag}}-riscv64
|
||||
- anchore/syft:{{.Tag}}-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:latest
|
||||
@@ -246,6 +289,7 @@ docker_manifests:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-amd64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-s390x
|
||||
|
||||
- name_template: anchore/syft:{{.Tag}}
|
||||
@@ -253,6 +297,7 @@ docker_manifests:
|
||||
- anchore/syft:{{.Tag}}-amd64
|
||||
- anchore/syft:{{.Tag}}-arm64v8
|
||||
- anchore/syft:{{.Tag}}-ppc64le
|
||||
- anchore/syft:{{.Tag}}-riscv64
|
||||
- anchore/syft:{{.Tag}}-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:{{.Tag}}
|
||||
@@ -260,6 +305,7 @@ docker_manifests:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-amd64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-s390x
|
||||
|
||||
# nonroot images...
|
||||
@@ -268,6 +314,7 @@ docker_manifests:
|
||||
- anchore/syft:{{.Tag}}-nonroot-amd64
|
||||
- anchore/syft:{{.Tag}}-nonroot-arm64v8
|
||||
- anchore/syft:{{.Tag}}-nonroot-ppc64le
|
||||
- anchore/syft:{{.Tag}}-nonroot-riscv64
|
||||
- anchore/syft:{{.Tag}}-nonroot-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:nonroot
|
||||
@@ -275,6 +322,7 @@ docker_manifests:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-amd64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
|
||||
|
||||
- name_template: anchore/syft:{{.Tag}}-nonroot
|
||||
@@ -282,6 +330,7 @@ docker_manifests:
|
||||
- anchore/syft:{{.Tag}}-nonroot-amd64
|
||||
- anchore/syft:{{.Tag}}-nonroot-arm64v8
|
||||
- anchore/syft:{{.Tag}}-nonroot-ppc64le
|
||||
- anchore/syft:{{.Tag}}-nonroot-riscv64
|
||||
- anchore/syft:{{.Tag}}-nonroot-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:{{.Tag}}-nonroot
|
||||
@@ -289,6 +338,7 @@ docker_manifests:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-amd64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-nonroot-s390x
|
||||
|
||||
# debug images...
|
||||
@@ -297,6 +347,7 @@ docker_manifests:
|
||||
- anchore/syft:{{.Tag}}-debug-amd64
|
||||
- anchore/syft:{{.Tag}}-debug-arm64v8
|
||||
- anchore/syft:{{.Tag}}-debug-ppc64le
|
||||
- anchore/syft:{{.Tag}}-debug-riscv64
|
||||
- anchore/syft:{{.Tag}}-debug-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:debug
|
||||
@@ -304,6 +355,7 @@ docker_manifests:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-amd64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
|
||||
|
||||
- name_template: anchore/syft:{{.Tag}}-debug
|
||||
@@ -311,6 +363,7 @@ docker_manifests:
|
||||
- anchore/syft:{{.Tag}}-debug-amd64
|
||||
- anchore/syft:{{.Tag}}-debug-arm64v8
|
||||
- anchore/syft:{{.Tag}}-debug-ppc64le
|
||||
- anchore/syft:{{.Tag}}-debug-riscv64
|
||||
- anchore/syft:{{.Tag}}-debug-s390x
|
||||
|
||||
- name_template: ghcr.io/anchore/syft:{{.Tag}}-debug
|
||||
@@ -318,6 +371,7 @@ docker_manifests:
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-amd64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-riscv64
|
||||
- ghcr.io/anchore/syft:{{.Tag}}-debug-s390x
|
||||
|
||||
sboms:
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
module github.com/anchore/syft/.make
|
||||
|
||||
go 1.25.8
|
||||
|
||||
require (
|
||||
github.com/anchore/go-make v0.4.0
|
||||
github.com/goccy/go-yaml v1.19.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
|
||||
golang.org/x/mod v0.35.0 // indirect
|
||||
golang.org/x/sys v0.44.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
github.com/anchore/go-make v0.4.0 h1:poFE4PXcHwvix2E8AhdM7YHZ15bMhZb+W02i3+qrP8M=
|
||||
github.com/anchore/go-make v0.4.0/go.mod h1:Nc/tkwQHW1d1Vi8+0rtS/vSrH6pxieaUQXLdrctn+8g=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
||||
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
||||
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/goccy/go-yaml"
|
||||
|
||||
. "github.com/anchore/go-make"
|
||||
"github.com/anchore/go-make/file"
|
||||
"github.com/anchore/go-make/git"
|
||||
"github.com/anchore/go-make/lang"
|
||||
"github.com/anchore/go-make/run"
|
||||
"github.com/anchore/go-make/tasks/golint"
|
||||
"github.com/anchore/go-make/tasks/goreleaser"
|
||||
"github.com/anchore/go-make/tasks/gotest"
|
||||
)
|
||||
|
||||
// taskfileDescriptions maps Taskfile.yaml task names to their `desc:` field.
|
||||
// Loaded at package init so wrap() can use Taskfile.yaml as the single source
|
||||
// of truth for wrapped-task descriptions.
|
||||
var taskfileDescriptions = mustReadTaskfileDescriptions()
|
||||
|
||||
func main() {
|
||||
Makefile(
|
||||
// shared anchore tasks
|
||||
golint.Tasks(),
|
||||
goreleaser.Tasks(),
|
||||
|
||||
// unit tests: exclude packages under any test/ directory (matches the syft
|
||||
// Taskfile's prior `grep -v` against test paths). Coverage threshold of 62%
|
||||
// preserves the prior coverage gate that used to live in scripts/coverage.py.
|
||||
gotest.Tasks(
|
||||
gotest.Name("unit"),
|
||||
gotest.ExcludeGlob("**/test/**"),
|
||||
gotest.CoverageThreshold(62),
|
||||
),
|
||||
|
||||
// integration tests: native go-make Task. The race-detector smoke against a
|
||||
// real image stays bundled here (RunsOn integration) so `make integration`
|
||||
// behaves like the Taskfile version did.
|
||||
gotest.Tasks(
|
||||
gotest.Name("integration"),
|
||||
gotest.IncludeGlob("./cmd/syft/internal/test/integration/..."),
|
||||
gotest.Verbose(),
|
||||
gotest.NoCoverage(),
|
||||
),
|
||||
Task{
|
||||
Name: "integration:race-smoke",
|
||||
Description: "exercise the CLI with the race detector",
|
||||
RunsOn: lang.List("integration"),
|
||||
Run: func() {
|
||||
Run("go run -race cmd/syft/main.go anchore/test_images:grype-quality-dotnet-69f15d2")
|
||||
},
|
||||
},
|
||||
|
||||
// cli tests: native go-make Task. Requires SYFT_BINARY_LOCATION pointing at
|
||||
// an *absolute* path to the snapshot binary. Intentionally does NOT depend
|
||||
// on snapshot: in CI we download a pre-built snapshot artifact and re-running
|
||||
// goreleaser here would both burn ~10m and clobber the downloaded binary.
|
||||
// Locally, the failure message tells you to run `make snapshot` first.
|
||||
Task{
|
||||
Name: "cli",
|
||||
Description: "Run CLI tests",
|
||||
RunsOn: lang.List("test"),
|
||||
Run: func() {
|
||||
bin := snapshotBinPath()
|
||||
if !file.Exists(bin) {
|
||||
panic(fmt.Sprintf("snapshot binary not found at %s; run `make snapshot` first", bin))
|
||||
}
|
||||
Log("testing binary: %s", bin)
|
||||
Run(
|
||||
"go test -count=1 -timeout=15m -v ./test/cli",
|
||||
run.Env("SYFT_BINARY_LOCATION", bin),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
||||
// default validation pipeline (replaces Taskfile `default`/`pr-validations`/`validations`).
|
||||
Task{
|
||||
Name: "default",
|
||||
Description: "Run all validation tasks",
|
||||
Dependencies: Deps("static-analysis", "test", "install-test"),
|
||||
},
|
||||
|
||||
// --- everything below is implemented in Taskfile.yaml and surfaced here
|
||||
// via wrap(). Descriptions come from Taskfile.yaml (single source of truth).
|
||||
|
||||
// static analysis extras
|
||||
wrap("check-json-schema-drift").RunOn("static-analysis"),
|
||||
wrap("check-capability-drift"),
|
||||
wrap("check-binary-fixture-size").RunOn("static-analysis"),
|
||||
|
||||
// test extras
|
||||
wrap("validate-cyclonedx-schema").RunOn("test"),
|
||||
wrap("test-utils").RunOn("test"),
|
||||
wrap("check-docker-cache").RunOn("test"),
|
||||
wrap("snapshot-smoke-test"),
|
||||
|
||||
// update commands
|
||||
wrap("update-format-golden-files"),
|
||||
|
||||
// fixture cache plumbing (heavy ORAS logic, lives in Taskfile).
|
||||
// refresh-fixtures hooks into "unit" so `make unit` triggers the
|
||||
// stale-cache detection + download just like `task unit` did on main
|
||||
// (its `deps: [tmpdir, fixtures]` is what kept the fixture cache fresh).
|
||||
wrap("fingerprints"),
|
||||
wrap("refresh-fixtures").RunOn("unit"),
|
||||
wrap("fixtures"),
|
||||
wrap("build-fixtures"),
|
||||
wrap("download-test-fixture-cache"),
|
||||
wrap("upload-test-fixture-cache"),
|
||||
wrap("show-test-image-cache"),
|
||||
|
||||
// install-script tests (delegates to test/install/Makefile)
|
||||
wrap("install-test"),
|
||||
wrap("install-test-cache-save"),
|
||||
wrap("install-test-cache-load"),
|
||||
wrap("install-test-ci-mac"),
|
||||
|
||||
// compare tests
|
||||
wrap("generate-compare-file"),
|
||||
wrap("compare-mac"),
|
||||
wrap("compare-linux"),
|
||||
wrap("compare-test-deb-package-install"),
|
||||
wrap("compare-test-rpm-package-install"),
|
||||
|
||||
// code/data generation (umbrella + per-target; each lives in Taskfile)
|
||||
wrap("generate"),
|
||||
wrap("generate-json-schema"),
|
||||
wrap("generate-license-list"),
|
||||
wrap("generate-cpe-dictionary-index"),
|
||||
wrap("generate-capabilities"),
|
||||
|
||||
// cleanup (each hooks into go-make's built-in `clean` label)
|
||||
wrap("clean-snapshot").RunOn("clean"),
|
||||
wrap("clean-docker-cache").RunOn("clean"),
|
||||
wrap("clean-oras-cache").RunOn("clean"),
|
||||
wrap("clean-cache").RunOn("clean"),
|
||||
wrap("clean-test-observations").RunOn("clean"),
|
||||
)
|
||||
}
|
||||
|
||||
// wrap creates a go-make Task that delegates execution to `task <name>`. The
|
||||
// task's description is pulled from Taskfile.yaml's `desc:` field — descriptions
|
||||
// for wrapped tasks must always live in Taskfile.yaml, never here.
|
||||
func wrap(name string) Task {
|
||||
desc, ok := taskfileDescriptions[name]
|
||||
if !ok || desc == "" {
|
||||
// loud-fail at startup so missing descs can't sneak through review.
|
||||
panic(fmt.Sprintf("Taskfile.yaml task %q is missing a `desc:` field; please add one", name))
|
||||
}
|
||||
return Task{
|
||||
Name: name,
|
||||
Description: desc,
|
||||
Run: func() { Run("task " + name) },
|
||||
}
|
||||
}
|
||||
|
||||
// mustReadTaskfileDescriptions parses Taskfile.yaml at the repo root and returns
|
||||
// a map of task name -> desc. Runs at package init time so wrap() can use it.
|
||||
func mustReadTaskfileDescriptions() map[string]string {
|
||||
root := git.Root()
|
||||
if root == "" {
|
||||
return nil
|
||||
}
|
||||
path := filepath.Join(root, "Taskfile.yaml")
|
||||
data, err := os.ReadFile(path) //nolint:gosec // G304: path resolved from git.Root()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var tf struct {
|
||||
Tasks map[string]struct {
|
||||
Desc string `yaml:"desc"`
|
||||
Aliases []string `yaml:"aliases"`
|
||||
} `yaml:"tasks"`
|
||||
}
|
||||
lang.Throw(yaml.Unmarshal(data, &tf))
|
||||
out := make(map[string]string, len(tf.Tasks))
|
||||
for name, t := range tf.Tasks {
|
||||
out[name] = t.Desc
|
||||
// aliases inherit the canonical task's description so wrap() can find them.
|
||||
for _, alias := range t.Aliases {
|
||||
out[alias] = t.Desc
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// snapshotBinPath replicates the SNAPSHOT_BIN computation from the prior Taskfile:
|
||||
// <repoRoot>/snapshot/<os>-build_<os>_<arch>/syft, where arch maps amd64->amd64_v1
|
||||
// and arm64->arm64_v8.0 to match goreleaser's per-target output directory naming.
|
||||
// Returns an absolute path: the cli tests' getSyftBinaryLocation contract requires
|
||||
// SYFT_BINARY_LOCATION to be absolute because subtests run with cmd.Dir = t.TempDir().
|
||||
func snapshotBinPath() string {
|
||||
osName := runtime.GOOS
|
||||
var arch string
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
arch = "amd64_v1"
|
||||
case "arm64":
|
||||
arch = "arm64_v8.0"
|
||||
default:
|
||||
arch = runtime.GOARCH
|
||||
}
|
||||
return filepath.Join(RootDir(), "snapshot", osName+"-build_"+osName+"_"+arch, "syft")
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
FROM gcr.io/distroless/static-debian12:latest AS build
|
||||
ARG DEBIAN_VERSION=12
|
||||
FROM gcr.io/distroless/static-debian${DEBIAN_VERSION}:latest AS build
|
||||
|
||||
FROM scratch
|
||||
# needed for version check HTTPS request
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
FROM gcr.io/distroless/static-debian12:debug-nonroot
|
||||
ARG DEBIAN_VERSION=12
|
||||
FROM gcr.io/distroless/static-debian${DEBIAN_VERSION}:debug-nonroot
|
||||
|
||||
# create the /tmp dir, which is needed for image content cache
|
||||
WORKDIR /tmp
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
FROM gcr.io/distroless/static-debian12:nonroot
|
||||
ARG DEBIAN_VERSION=12
|
||||
FROM gcr.io/distroless/static-debian${DEBIAN_VERSION}:nonroot
|
||||
|
||||
# create the /tmp dir, which is needed for image content cache
|
||||
WORKDIR /tmp
|
||||
|
||||
@@ -1,46 +1,18 @@
|
||||
OWNER = anchore
|
||||
PROJECT = syft
|
||||
# `test` and `snapshot` have matching directory names in this repo, so make would
|
||||
# refuse to run them without an explicit .PHONY (Nothing to be done for ...).
|
||||
.PHONY: test snapshot
|
||||
test:
|
||||
@go run -C .make . test
|
||||
|
||||
TOOL_DIR = .tool
|
||||
BINNY = $(TOOL_DIR)/binny
|
||||
TASK = $(TOOL_DIR)/task
|
||||
snapshot:
|
||||
@go run -C .make . snapshot
|
||||
|
||||
.DEFAULT_GOAL := make-default
|
||||
.PHONY: *
|
||||
.DEFAULT_GOAL: make-default
|
||||
|
||||
## Bootstrapping targets #################################
|
||||
make-default:
|
||||
@go run -C .make .
|
||||
|
||||
# note: we need to assume that binny and task have not already been installed
|
||||
$(BINNY):
|
||||
@mkdir -p $(TOOL_DIR)
|
||||
@curl -sSfL https://get.anchore.io/binny | sh -s -- -b $(TOOL_DIR)
|
||||
|
||||
# note: we need to assume that binny and task have not already been installed
|
||||
.PHONY: task
|
||||
$(TASK) task: $(BINNY)
|
||||
@$(BINNY) install task -q
|
||||
|
||||
.PHONY: ci-bootstrap-go
|
||||
ci-bootstrap-go:
|
||||
go mod download
|
||||
|
||||
# this is a bootstrapping catch-all, where if the target doesn't exist, we'll ensure the tools are installed and then try again
|
||||
.DEFAULT:
|
||||
%:
|
||||
@make --silent $(TASK)
|
||||
@$(TASK) $@
|
||||
|
||||
## Shim targets #################################
|
||||
|
||||
.PHONY: make-default
|
||||
make-default: $(TASK)
|
||||
@# run the default task in the taskfile
|
||||
@$(TASK)
|
||||
|
||||
# for those of us that can't seem to kick the habit of typing `make ...` lets wrap the superior `task` tool
|
||||
TASKS := $(shell bash -c "test -f $(TASK) && NO_COLOR=1 $(TASK) -l | grep '^\* ' | cut -d' ' -f2 | tr -d ':' | tr '\n' ' '" ) $(shell bash -c "test -f $(TASK) && NO_COLOR=1 $(TASK) -l | grep 'aliases:' | cut -d ':' -f 3 | tr '\n' ' ' | tr -d ','")
|
||||
|
||||
.PHONY: $(TASKS)
|
||||
$(TASKS): $(TASK)
|
||||
@$(TASK) $@
|
||||
|
||||
help: $(TASK)
|
||||
@$(TASK) -l
|
||||
@go run -C .make . $@
|
||||
|
||||
+20
@@ -14,3 +14,23 @@ affected versions, and, if known, mitigations for the issue.
|
||||
All support will be made on a best effort basis, so please indicate the "urgency level" of the vulnerability as Critical, High, Medium or Low.
|
||||
|
||||
For more details, see our [security policy documentation](https://oss.anchore.com/docs/contributing/security/).
|
||||
|
||||
## Trust Boundary
|
||||
|
||||
Syft is a tool to scan content and product an SBOM. Syft is not a tool designed to scan malicious content. Detecting and properly reporting on purposely malicious artifacts is outside the scope of Syft's expected operating environment.
|
||||
|
||||
There are many possible ways for malicious content to cause Syft to become confused or fail to include results in an SBOM. We do not consider this to be a security vulnerability.
|
||||
|
||||
**Examples**
|
||||
- Removing or altering a package lock file
|
||||
- Removing or altering an RPM or DEB database
|
||||
- A malicious archive that Syft will skip but the runtime may not
|
||||
- Self modifying systems that change state when running
|
||||
|
||||
We consider the security trust boundary for Syft to be anything that causes problems for the overall system running Syft, or Syft operating in a way that is dangerous to itself, the system, or the operator.
|
||||
|
||||
**Examples**
|
||||
- Filling up temp space permanently
|
||||
- Syft executing arbitrary code when scanning an artifact
|
||||
- Syft leaking secrets from the environment or configuration files into logs or SBOMs
|
||||
- Syft operating outside of the expected artifact or directory (directory traversal)
|
||||
|
||||
+71
-270
@@ -1,6 +1,11 @@
|
||||
|
||||
version: "3"
|
||||
|
||||
# NOTE: most generic tasks (static-analysis, format, lint, unit, snapshot, release,
|
||||
# changelog, ci-release, etc.) are now provided natively by anchore/go-make and
|
||||
# defined in .make/main.go. This file holds the syft-specific tasks that go-make
|
||||
# wraps via `wrap("<name>")` calls — keep descriptions (`desc:`) populated so they
|
||||
# show up in `make help`.
|
||||
|
||||
includes:
|
||||
generate:cpe-index: ./task.d/generate/cpe-index.yaml
|
||||
|
||||
@@ -8,7 +13,10 @@ vars:
|
||||
OWNER: anchore
|
||||
PROJECT: syft
|
||||
|
||||
CACHE_IMAGE: ghcr.io/{{ .OWNER }}/{{ .PROJECT }}/test-fixture-cache:latest
|
||||
# v1: when fixtures were located at test-fixtures dirs
|
||||
# v2: migration to testdata dirs
|
||||
CACHE_REPO: oss-cache
|
||||
CACHE_IMAGE: ghcr.io/{{ .OWNER }}/{{ .CACHE_REPO }}/syft-test-fixture-cache:v2
|
||||
|
||||
# static file dirs
|
||||
TOOL_DIR: .tool
|
||||
@@ -22,11 +30,7 @@ vars:
|
||||
YQ: "{{ .TOOL_DIR }}/yq"
|
||||
TASK: "{{ .TOOL_DIR }}/task"
|
||||
|
||||
# used for changelog generation
|
||||
CHANGELOG: CHANGELOG.md
|
||||
NEXT_VERSION: VERSION
|
||||
|
||||
# used for snapshot builds
|
||||
# used for snapshot bin discovery in compare/install tasks
|
||||
OS:
|
||||
sh: uname -s | tr '[:upper:]' '[:lower:]'
|
||||
ARCH:
|
||||
@@ -39,11 +43,6 @@ vars:
|
||||
# e.g. when installing snapshot debs from a local path, ./ forces the deb to be installed in the current working directory instead of referencing a package name
|
||||
SNAPSHOT_DIR: ./snapshot
|
||||
SNAPSHOT_BIN: "{{ .PROJECT_ROOT }}/{{ .SNAPSHOT_DIR }}/{{ .OS }}-build_{{ .OS }}_{{ .ARCH }}/{{ .PROJECT }}"
|
||||
SNAPSHOT_CMD: "{{ .TOOL_DIR }}/goreleaser release --config {{ .TMP_DIR }}/goreleaser.yaml --clean --snapshot --skip=publish --skip=sign"
|
||||
BUILD_CMD: "{{ .TOOL_DIR }}/goreleaser build --config {{ .TMP_DIR }}/goreleaser.yaml --clean --snapshot --single-target"
|
||||
RELEASE_CMD: "{{ .TOOL_DIR }}/goreleaser release --clean --release-notes {{ .CHANGELOG }}"
|
||||
VERSION:
|
||||
sh: git describe --dirty --always --tags
|
||||
|
||||
# used for install and acceptance testing
|
||||
COMPARE_DIR: ./test/compare
|
||||
@@ -54,44 +53,10 @@ env:
|
||||
|
||||
tasks:
|
||||
|
||||
## High-level tasks #################################
|
||||
|
||||
default:
|
||||
desc: Run all validation tasks
|
||||
aliases:
|
||||
- pr-validations
|
||||
- validations
|
||||
cmds:
|
||||
- task: static-analysis
|
||||
- task: test
|
||||
- task: install-test
|
||||
|
||||
static-analysis:
|
||||
desc: Run all static analysis tasks
|
||||
cmds:
|
||||
- task: check-go-mod-tidy
|
||||
- task: check-licenses
|
||||
- task: lint
|
||||
- task: check-json-schema-drift
|
||||
- task: check-capability-drift
|
||||
- task: check-binary-fixture-size
|
||||
|
||||
test:
|
||||
desc: Run all levels of test
|
||||
cmds:
|
||||
- task: unit
|
||||
- task: integration
|
||||
- task: validate-cyclonedx-schema
|
||||
- task: test-utils
|
||||
- task: snapshot
|
||||
- task: cli
|
||||
- task: check-docker-cache
|
||||
|
||||
## Bootstrap tasks #################################
|
||||
## Bootstrap (internal helpers used by other Taskfile tasks) ###############
|
||||
|
||||
binny:
|
||||
internal: true
|
||||
# desc: Get the binny tool
|
||||
generates:
|
||||
- "{{ .TOOL_DIR }}/binny"
|
||||
status:
|
||||
@@ -100,10 +65,8 @@ tasks:
|
||||
silent: true
|
||||
|
||||
tools:
|
||||
desc: Install all tools needed for CI and local development
|
||||
internal: true
|
||||
deps: [binny]
|
||||
aliases:
|
||||
- bootstrap
|
||||
generates:
|
||||
- ".binny.yaml"
|
||||
- "{{ .TOOL_DIR }}/*"
|
||||
@@ -112,79 +75,14 @@ tasks:
|
||||
cmd: "{{ .TOOL_DIR }}/binny install -v"
|
||||
silent: true
|
||||
|
||||
update-tools:
|
||||
desc: Update pinned versions of all tools to their latest available versions
|
||||
deps: [binny]
|
||||
generates:
|
||||
- ".binny.yaml"
|
||||
- "{{ .TOOL_DIR }}/*"
|
||||
cmd: "{{ .TOOL_DIR }}/binny update -v"
|
||||
silent: true
|
||||
|
||||
list-tools:
|
||||
desc: List all tools needed for CI and local development
|
||||
deps: [binny]
|
||||
cmd: "{{ .TOOL_DIR }}/binny list"
|
||||
silent: true
|
||||
|
||||
list-tool-updates:
|
||||
desc: List all tools that are not up to date relative to the binny config
|
||||
deps: [binny]
|
||||
cmd: "{{ .TOOL_DIR }}/binny list --updates"
|
||||
silent: true
|
||||
|
||||
tmpdir:
|
||||
internal: true
|
||||
silent: true
|
||||
generates:
|
||||
- "{{ .TMP_DIR }}"
|
||||
cmd: "mkdir -p {{ .TMP_DIR }}"
|
||||
|
||||
## Static analysis tasks #################################
|
||||
|
||||
format:
|
||||
desc: Auto-format all source code
|
||||
deps: [tools]
|
||||
cmds:
|
||||
- gofmt -w -s .
|
||||
- "{{ .TOOL_DIR }}/gosimports -local github.com/anchore -w ."
|
||||
- go mod tidy
|
||||
|
||||
lint-fix:
|
||||
desc: Auto-format all source code + run golangci lint fixers
|
||||
deps: [tools]
|
||||
cmds:
|
||||
- task: format
|
||||
- "{{ .TOOL_DIR }}/golangci-lint run --tests=false --fix"
|
||||
|
||||
lint:
|
||||
desc: Run gofmt + golangci lint checks
|
||||
vars:
|
||||
BAD_FMT_FILES:
|
||||
sh: gofmt -l -s .
|
||||
BAD_FILE_NAMES:
|
||||
sh: "find . | grep -e ':' || true"
|
||||
deps: [tools]
|
||||
cmds:
|
||||
# ensure there are no go fmt differences
|
||||
- cmd: 'test -z "{{ .BAD_FMT_FILES }}" || (echo "files with gofmt issues: [{{ .BAD_FMT_FILES }}]"; exit 1)'
|
||||
silent: true
|
||||
# ensure there are no files with ":" in it (a known back case in the go ecosystem)
|
||||
- cmd: 'test -z "{{ .BAD_FILE_NAMES }}" || (echo "files with bad names: [{{ .BAD_FILE_NAMES }}]"; exit 1)'
|
||||
silent: true
|
||||
# run linting
|
||||
- "{{ .TOOL_DIR }}/golangci-lint run --tests=false"
|
||||
|
||||
|
||||
check-licenses:
|
||||
# desc: Ensure transitive dependencies are compliant with the current license policy
|
||||
deps: [tools]
|
||||
cmd: "{{ .TOOL_DIR }}/bouncer check ./..."
|
||||
|
||||
check-go-mod-tidy:
|
||||
# desc: Ensure go.mod and go.sum are up to date
|
||||
cmds:
|
||||
- cmd: .github/scripts/go-mod-tidy-check.sh && echo "go.mod and go.sum are tidy!"
|
||||
silent: true
|
||||
## Static analysis extras #################################################
|
||||
|
||||
check-json-schema-drift:
|
||||
desc: Ensure there is no drift between the JSON schema and the code
|
||||
@@ -199,10 +97,10 @@ tasks:
|
||||
check-binary-fixture-size:
|
||||
desc: Ensure that the binary test fixtures are not too large
|
||||
cmds:
|
||||
- .github/scripts/check_binary_fixture_size.sh syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets
|
||||
- .github/scripts/check_binary_fixture_size.sh syft/pkg/cataloger/binary/testdata/classifiers/snippets
|
||||
|
||||
## Test extras ############################################################
|
||||
|
||||
## Testing tasks #################################
|
||||
update-format-golden-files:
|
||||
desc: "Update golden (i.e. snapshot) files used by unit tests"
|
||||
cmds:
|
||||
@@ -212,63 +110,36 @@ tasks:
|
||||
- go test ./syft/format/cyclonedxjson -update-cyclonedx-json
|
||||
- go test ./syft/format/syftjson -update-json
|
||||
|
||||
unit:
|
||||
desc: Run unit tests
|
||||
deps:
|
||||
- tmpdir
|
||||
- fixtures
|
||||
vars:
|
||||
TEST_PKGS:
|
||||
sh: "go list ./... | grep -v {{ .OWNER }}/{{ .PROJECT }}/test | grep -v {{ .OWNER }}/{{ .PROJECT }}/cmd/syft/internal/test | tr '\n' ' '"
|
||||
|
||||
# unit test coverage threshold (in % coverage)
|
||||
COVERAGE_THRESHOLD: 62
|
||||
cmds:
|
||||
- task: clean-test-observations
|
||||
- "go test -coverprofile {{ .TMP_DIR }}/unit-coverage-details.txt {{ .TEST_PKGS }}"
|
||||
- cmd: ".github/scripts/coverage.py {{ .COVERAGE_THRESHOLD }} {{ .TMP_DIR }}/unit-coverage-details.txt"
|
||||
silent: true
|
||||
|
||||
integration:
|
||||
desc: Run integration tests
|
||||
cmds:
|
||||
- "go test -v ./cmd/syft/internal/test/integration"
|
||||
# exercise most of the CLI with the data race detector
|
||||
# we use a larger image to ensure we're using multiple catalogers at a time
|
||||
- "go run -race cmd/syft/main.go anchore/test_images:grype-quality-dotnet-69f15d2"
|
||||
|
||||
validate-cyclonedx-schema:
|
||||
desc: Validate that Syft produces valid CycloneDX documents
|
||||
cmds:
|
||||
- "cd schema/cyclonedx && make"
|
||||
|
||||
cli:
|
||||
desc: Run CLI tests
|
||||
deps: [tools]
|
||||
cmds:
|
||||
- cmd: "echo 'testing binary: {{ .SNAPSHOT_BIN }}'"
|
||||
silent: true
|
||||
- cmd: "test -f {{ .SNAPSHOT_BIN }} || (find {{ .SNAPSHOT_DIR }} && echo '\nno snapshot found for {{ .SNAPSHOT_BIN }}' && false)"
|
||||
silent: true
|
||||
|
||||
- "go test -count=1 -timeout=15m -v ./test/cli"
|
||||
env:
|
||||
SYFT_BINARY_LOCATION: "{{ .SNAPSHOT_BIN }}"
|
||||
|
||||
test-utils:
|
||||
desc: Run tests for pipeline utils
|
||||
cmds:
|
||||
- cmd: .github/scripts/labeler_test.py
|
||||
|
||||
snapshot-smoke-test:
|
||||
desc: Run a smoke test on the snapshot builds + docker images
|
||||
cmds:
|
||||
- cmd: "echo 'testing snapshot binary: {{ .SNAPSHOT_BIN }}'"
|
||||
silent: true
|
||||
- cmd: "test -f {{ .SNAPSHOT_BIN }} || (find {{ .SNAPSHOT_DIR }} && echo '\nno snapshot found for {{ .SNAPSHOT_BIN }}' && false)"
|
||||
silent: true
|
||||
- "{{ .SNAPSHOT_BIN }} version"
|
||||
- "{{ .SNAPSHOT_BIN }} scan alpine:latest"
|
||||
- docker run --rm anchore/syft:latest version
|
||||
- docker run --rm anchore/syft:latest scan alpine:latest
|
||||
|
||||
## Test-fixture-related targets #################################
|
||||
## Test-fixture-related targets ###########################################
|
||||
|
||||
fingerprints:
|
||||
desc: Generate fingerprints for all non-docker test fixture
|
||||
desc: Generate fingerprints for all non-docker test fixtures
|
||||
silent: true
|
||||
# this will look for `test-fixtures/Makefile` and invoke the `fingerprint` target to calculate all cache input fingerprint files
|
||||
# this will look for `testdata/Makefile` and invoke the `fingerprint` target to calculate all cache input fingerprint files
|
||||
generates:
|
||||
- '**/test-fixtures/**/*.fingerprint'
|
||||
- '**/testdata/**/*.fingerprint'
|
||||
- test/install/cache.fingerprint
|
||||
cmds:
|
||||
- |
|
||||
@@ -277,18 +148,12 @@ tasks:
|
||||
RESET='\033[0m'
|
||||
|
||||
echo -e "${YELLOW}creating fingerprint files for non-docker fixtures...${RESET}"
|
||||
for dir in $(find . -type d -name 'test-fixtures'); do
|
||||
for dir in $(find . -type d -name 'testdata'); do
|
||||
if [ -f "$dir/Makefile" ]; then
|
||||
# for debugging...
|
||||
#echo -e "${YELLOW}• calculating fingerprints in $dir... ${RESET}"
|
||||
|
||||
(make -C "$dir" fingerprint)
|
||||
fi
|
||||
done
|
||||
|
||||
# for debugging...
|
||||
# echo -e "generated all fixture fingerprints"
|
||||
|
||||
- .github/scripts/fingerprint_docker_fixtures.py
|
||||
- |
|
||||
# if DOWNLOAD_TEST_FIXTURE_CACHE is set to 'false', then we don't need to calculate the fingerprint for the cache
|
||||
@@ -370,7 +235,7 @@ tasks:
|
||||
build-fixtures:
|
||||
desc: Generate all non-docker test fixtures
|
||||
silent: true
|
||||
# this will look for `test-fixtures/Makefile` and invoke the `fixtures` target to generate any and all test fixtures
|
||||
# this will look for `testdata/Makefile` and invoke the `fixtures` target to generate any and all test fixtures
|
||||
cmds:
|
||||
- |
|
||||
# we want to stop on the first build error
|
||||
@@ -381,7 +246,7 @@ tasks:
|
||||
RESET='\033[0m'
|
||||
|
||||
# Use a for loop with command substitution to avoid subshell issues
|
||||
for dir in $(find . -type d -name 'test-fixtures'); do
|
||||
for dir in $(find . -type d -name 'testdata'); do
|
||||
if [ -f "$dir/Makefile" ]; then
|
||||
echo -e "${YELLOW}${BOLD}generating fixtures in $dir${RESET}"
|
||||
make -C "$dir" fixtures
|
||||
@@ -423,19 +288,20 @@ tasks:
|
||||
done
|
||||
oras_command+=" {{ .CACHE_PATHS_FILE }}"
|
||||
|
||||
oras_command+=" --annotation org.opencontainers.image.source=https://github.com/{{ .OWNER }}/{{ .PROJECT }}"
|
||||
oras_command+=" --annotation org.opencontainers.image.source=https://github.com/{{ .OWNER }}/{{ .CACHE_REPO }}"
|
||||
oras_command+=" --annotation fingerprint=$(cat {{ .CACHE_PATHS_FILE }} | {{ .YQ }} -r '.digest')"
|
||||
|
||||
echo "Executing: $oras_command"
|
||||
eval $oras_command
|
||||
|
||||
show-test-image-cache:
|
||||
desc: Print the on-disk + docker daemon state of the stereoscope fixture image cache
|
||||
silent: true
|
||||
cmds:
|
||||
- "echo 'Docker daemon cache:'"
|
||||
- "docker images --format '{{`{{.ID}}`}} {{`{{.Repository}}`}}:{{`{{.Tag}}`}}' | grep stereoscope-fixture- | sort"
|
||||
- "echo '\nTar cache:'"
|
||||
- 'find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" | sort'
|
||||
- 'find . -type f -wholename "**/testdata/cache/stereoscope-fixture-*.tar" | sort'
|
||||
|
||||
check-docker-cache:
|
||||
desc: Ensure docker caches aren't using too much disk space
|
||||
@@ -450,28 +316,36 @@ tasks:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## install.sh testing targets #################################
|
||||
## install.sh testing targets #############################################
|
||||
|
||||
install-test:
|
||||
desc: Run install.sh test suite (delegates to test/install/Makefile)
|
||||
cmds:
|
||||
- "cd test/install && make"
|
||||
|
||||
install-test-cache-save:
|
||||
desc: Save the install.sh test image cache (delegates to test/install/Makefile)
|
||||
cmds:
|
||||
- "cd test/install && make save"
|
||||
|
||||
install-test-cache-load:
|
||||
desc: Load the install.sh test image cache (delegates to test/install/Makefile)
|
||||
cmds:
|
||||
- "cd test/install && make load"
|
||||
|
||||
install-test-ci-mac:
|
||||
desc: Run install.sh CI test suite on macOS (delegates to test/install/Makefile)
|
||||
cmds:
|
||||
- "cd test/install && make ci-test-mac"
|
||||
|
||||
## Compare-test targets ###################################################
|
||||
|
||||
generate-compare-file:
|
||||
cmd: "go run ./cmd/syft {{ .COMPARE_TEST_IMAGE }} -o json > {{ .COMPARE_DIR }}/test-fixtures/acceptance-{{ .COMPARE_TEST_IMAGE }}.json"
|
||||
desc: Generate the acceptance comparison reference JSON for the current compare image
|
||||
cmd: "go run ./cmd/syft {{ .COMPARE_TEST_IMAGE }} -o json > {{ .COMPARE_DIR }}/testdata/acceptance-{{ .COMPARE_TEST_IMAGE }}.json"
|
||||
|
||||
compare-mac:
|
||||
desc: Run macOS install + acceptance comparison against the snapshot build
|
||||
deps: [tmpdir]
|
||||
cmd: |
|
||||
{{ .COMPARE_DIR }}/mac.sh \
|
||||
@@ -481,11 +355,13 @@ tasks:
|
||||
{{ .TMP_DIR }}
|
||||
|
||||
compare-linux:
|
||||
desc: Run Linux install + acceptance comparison (deb + rpm) against the snapshot build
|
||||
cmds:
|
||||
- task: compare-test-deb-package-install
|
||||
- task: compare-test-rpm-package-install
|
||||
|
||||
compare-test-deb-package-install:
|
||||
desc: Run Linux .deb install + acceptance comparison against the snapshot build
|
||||
deps: [tmpdir]
|
||||
cmd: |
|
||||
{{ .COMPARE_DIR }}/deb.sh \
|
||||
@@ -495,6 +371,7 @@ tasks:
|
||||
{{ .TMP_DIR }}
|
||||
|
||||
compare-test-rpm-package-install:
|
||||
desc: Run Linux .rpm install + acceptance comparison against the snapshot build
|
||||
deps: [tmpdir]
|
||||
cmd: |
|
||||
{{ .COMPARE_DIR }}/rpm.sh \
|
||||
@@ -504,7 +381,7 @@ tasks:
|
||||
{{ .TMP_DIR }}
|
||||
|
||||
|
||||
## Code and data generation targets #################################
|
||||
## Code and data generation targets ######################################
|
||||
|
||||
generate:
|
||||
desc: Add data generation tasks
|
||||
@@ -537,11 +414,16 @@ tasks:
|
||||
deps:
|
||||
- tmpdir
|
||||
- fixtures
|
||||
vars:
|
||||
# set REFRESH=true to run package tests first and refresh test observations (default: true)
|
||||
REFRESH: '{{ .REFRESH | default "true" }}'
|
||||
cmds:
|
||||
# remove all test observations prior to regenerating
|
||||
- task: clean-test-observations
|
||||
if: '{{ eq .REFRESH "true" }}'
|
||||
# this is required to update test observations; such evidence is used to update the packages/*.yaml
|
||||
- "go test ./syft/pkg/... -count=1"
|
||||
- cmd: "go test ./syft/pkg/... -count=1"
|
||||
if: '{{ eq .REFRESH "true" }}'
|
||||
- "go generate ./internal/capabilities/..."
|
||||
- "gofmt -s -w ./internal/capabilities"
|
||||
# now that we have the latest capabilities, run completeness tests to ensure this is self-consistent
|
||||
@@ -549,95 +431,7 @@ tasks:
|
||||
- "SYFT_ENABLE_COMPLETENESS_TESTS=true go test -p 1 ./internal/capabilities/... -count=1"
|
||||
|
||||
|
||||
## Build-related targets #################################
|
||||
|
||||
build:
|
||||
desc: Build the project
|
||||
deps: [tools, tmpdir]
|
||||
generates:
|
||||
- "{{ .PROJECT }}"
|
||||
cmds:
|
||||
- silent: true
|
||||
cmd: |
|
||||
echo "dist: {{ .SNAPSHOT_DIR }}" > {{ .TMP_DIR }}/goreleaser.yaml
|
||||
cat .goreleaser.yaml >> {{ .TMP_DIR }}/goreleaser.yaml
|
||||
|
||||
- "{{ .BUILD_CMD }}"
|
||||
|
||||
snapshot:
|
||||
desc: Create a snapshot release
|
||||
aliases:
|
||||
- build
|
||||
deps: [tools, tmpdir]
|
||||
sources:
|
||||
- cmd/**/*.go
|
||||
- syft/**/*.go
|
||||
- internal/**/*.go
|
||||
method: checksum
|
||||
generates:
|
||||
- "{{ .SNAPSHOT_BIN }}"
|
||||
cmds:
|
||||
- silent: true
|
||||
cmd: |
|
||||
echo "dist: {{ .SNAPSHOT_DIR }}" > {{ .TMP_DIR }}/goreleaser.yaml
|
||||
cat .goreleaser.yaml >> {{ .TMP_DIR }}/goreleaser.yaml
|
||||
|
||||
- "{{ .SNAPSHOT_CMD }}"
|
||||
|
||||
snapshot-smoke-test:
|
||||
desc: Run a smoke test on the snapshot builds + docker images
|
||||
cmds:
|
||||
- cmd: "echo 'testing snapshot binary: {{ .SNAPSHOT_BIN }}'"
|
||||
silent: true
|
||||
- cmd: "test -f {{ .SNAPSHOT_BIN }} || (find {{ .SNAPSHOT_DIR }} && echo '\nno snapshot found for {{ .SNAPSHOT_BIN }}' && false)"
|
||||
silent: true
|
||||
- "{{ .SNAPSHOT_BIN }} version"
|
||||
- "{{ .SNAPSHOT_BIN }} scan alpine:latest"
|
||||
- docker run --rm anchore/syft:latest version
|
||||
- docker run --rm anchore/syft:latest scan alpine:latest
|
||||
|
||||
changelog:
|
||||
desc: Generate a changelog
|
||||
deps: [tools]
|
||||
generates:
|
||||
- "{{ .CHANGELOG }}"
|
||||
- "{{ .NEXT_VERSION }}"
|
||||
cmds:
|
||||
- "{{ .TOOL_DIR }}/chronicle -vv -n --version-file {{ .NEXT_VERSION }} > {{ .CHANGELOG }}"
|
||||
- "{{ .TOOL_DIR }}/glow -w 0 {{ .CHANGELOG }}"
|
||||
|
||||
|
||||
## Release targets #################################
|
||||
|
||||
release:
|
||||
desc: Create a release
|
||||
interactive: true
|
||||
deps: [tools]
|
||||
cmds:
|
||||
- cmd: .github/scripts/trigger-release.sh
|
||||
silent: true
|
||||
|
||||
|
||||
## CI-only targets #################################
|
||||
|
||||
ci-check:
|
||||
# desc: "[CI only] Are you in CI?"
|
||||
cmds:
|
||||
- cmd: .github/scripts/ci-check.sh
|
||||
silent: true
|
||||
|
||||
ci-release:
|
||||
# desc: "[CI only] Create a release"
|
||||
deps: [tools]
|
||||
cmds:
|
||||
- task: ci-check
|
||||
- "{{ .TOOL_DIR }}/chronicle -vvv > CHANGELOG.md"
|
||||
- cmd: "cat CHANGELOG.md"
|
||||
silent: true
|
||||
- "{{ .RELEASE_CMD }}"
|
||||
|
||||
|
||||
## Cleanup targets #################################
|
||||
## Cleanup targets ########################################################
|
||||
|
||||
clean-snapshot:
|
||||
desc: Remove any snapshot builds
|
||||
@@ -648,7 +442,7 @@ tasks:
|
||||
clean-docker-cache:
|
||||
desc: Remove all docker cache tars and images from the daemon
|
||||
cmds:
|
||||
- find . -type d -wholename "**/test-fixtures/cache" | xargs rm -rf
|
||||
- find . -type d -wholename "**/testdata/cache" | xargs rm -rf
|
||||
- docker images --format '{{`{{.ID}}`}} {{`{{.Repository}}`}}' | grep stereoscope-fixture- | awk '{print $1}' | uniq | xargs -r docker rmi --force
|
||||
|
||||
clean-oras-cache:
|
||||
@@ -659,13 +453,14 @@ tasks:
|
||||
desc: Remove all image docker tar cache, images from the docker daemon, and ephemeral test fixtures
|
||||
cmds:
|
||||
- task: clean-docker-cache
|
||||
- task: prune-orphan-fingerprints
|
||||
- |
|
||||
BOLD='\033[1m'
|
||||
YELLOW='\033[0;33m'
|
||||
RESET='\033[0m'
|
||||
|
||||
# Use a for loop with command substitution to avoid subshell issues
|
||||
for dir in $(find . -type d -name 'test-fixtures'); do
|
||||
for dir in $(find . -type d -name 'testdata'); do
|
||||
if [ -f "$dir/Makefile" ]; then
|
||||
echo -e "${YELLOW}${BOLD}deleting ephemeral test fixtures in $dir${RESET}"
|
||||
(make -C "$dir" clean)
|
||||
@@ -674,7 +469,13 @@ tasks:
|
||||
echo -e "${BOLD}Deleted all ephemeral test fixtures${RESET}"
|
||||
- rm -f {{ .LAST_CACHE_PULL_FILE }} {{ .CACHE_PATHS_FILE }}
|
||||
|
||||
clean-test-observations:
|
||||
desc: Remove all test observations (i.e. test-fixtures/test-observations.json)
|
||||
prune-orphan-fingerprints:
|
||||
desc: Remove *.fingerprint files left behind by moved/deleted catalogers
|
||||
silent: true
|
||||
cmds:
|
||||
- find . -type f -wholename "**/test-fixtures/test-observations.json" | xargs rm -f
|
||||
- .github/scripts/prune_orphan_fingerprints.py
|
||||
|
||||
clean-test-observations:
|
||||
desc: Remove all test observations (i.e. testdata/test-observations.json)
|
||||
cmds:
|
||||
- find . -type f -wholename "**/testdata/test-observations.json" | xargs rm -f
|
||||
|
||||
@@ -219,7 +219,7 @@ func (l attestLogFrame) View() string {
|
||||
sb := strings.Builder{}
|
||||
|
||||
for _, line := range l.lines {
|
||||
sb.WriteString(fmt.Sprintf(" %s %s\n", l.borderStype.Render("░░"), line))
|
||||
fmt.Fprintf(&sb, " %s %s\n", l.borderStype.Render("░░"), line)
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
|
||||
@@ -49,7 +49,7 @@ func AppClioSetupConfig(id clio.Identification, out io.Writer) *clio.SetupConfig
|
||||
},
|
||||
).
|
||||
WithPostRuns(func(_ *clio.State, _ error) {
|
||||
stereoscope.Cleanup()
|
||||
stereoscope.Cleanup() //nolint:staticcheck // we don't have access to the image object here
|
||||
})
|
||||
return clioCfg
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func Attest(app clio.Application) *cobra.Command {
|
||||
Use: "attest --output [FORMAT] <IMAGE>",
|
||||
Short: "Generate an SBOM as an attestation for the given [SOURCE] container image",
|
||||
Long: "Generate a packaged-based Software Bill Of Materials (SBOM) from a container image as the predicate of an in-toto attestation that will be uploaded to the image registry",
|
||||
Example: internal.Tprintf(attestHelp, map[string]interface{}{
|
||||
Example: internal.Tprintf(attestHelp, map[string]any{
|
||||
"appName": id.Name,
|
||||
"command": "attest",
|
||||
}),
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -248,12 +249,7 @@ func renderCatalogerInfoJSON(doc *capabilities.Document, catalogers []capabiliti
|
||||
|
||||
// isDeprecatedCataloger checks if a cataloger is deprecated based on its selectors
|
||||
func isDeprecatedCataloger(selectors []string) bool {
|
||||
for _, selector := range selectors {
|
||||
if selector == "deprecated" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(selectors, "deprecated")
|
||||
}
|
||||
|
||||
// convertDetectorPackages converts detector package info to the JSON output format
|
||||
@@ -452,7 +448,7 @@ func extractArrayCapability(caps capabilities.CapabilitySet, name string) string
|
||||
if len(v) > 0 {
|
||||
return strings.Join(v, ", ")
|
||||
}
|
||||
case []interface{}:
|
||||
case []any:
|
||||
if len(v) > 0 {
|
||||
strs := make([]string, 0, len(v))
|
||||
for _, item := range v {
|
||||
@@ -475,7 +471,7 @@ func extractNodesCapability(caps capabilities.CapabilitySet) string {
|
||||
switch v := cap.Default.(type) {
|
||||
case []string:
|
||||
return formatDepthStringArray(v)
|
||||
case []interface{}:
|
||||
case []any:
|
||||
return formatDepthInterfaceArray(v)
|
||||
}
|
||||
return noStyle.Render("·")
|
||||
@@ -496,7 +492,7 @@ func formatDepthStringArray(v []string) string {
|
||||
}
|
||||
|
||||
// formatDepthInterfaceArray formats a []interface{} dependency depth value
|
||||
func formatDepthInterfaceArray(v []interface{}) string {
|
||||
func formatDepthInterfaceArray(v []any) string {
|
||||
if len(v) == 0 {
|
||||
return noStyle.Render("·")
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func Convert(app clio.Application) *cobra.Command {
|
||||
Use: "convert [SOURCE-SBOM] -o [FORMAT]",
|
||||
Short: "Convert between SBOM formats",
|
||||
Long: "[Experimental] Convert SBOM files to, and from, SPDX, CycloneDX and Syft's format. For more info about data loss between formats see https://github.com/anchore/syft/wiki/format-conversion",
|
||||
Example: internal.Tprintf(convertExample, map[string]interface{}{
|
||||
Example: internal.Tprintf(convertExample, map[string]any{
|
||||
"appName": id.Name,
|
||||
"command": "convert",
|
||||
}),
|
||||
|
||||
@@ -18,7 +18,7 @@ func Packages(app clio.Application, scanCmd *cobra.Command) *cobra.Command {
|
||||
Short: scanCmd.Short,
|
||||
Long: scanCmd.Long,
|
||||
Args: scanCmd.Args,
|
||||
Example: internal.Tprintf(scanHelp, map[string]interface{}{
|
||||
Example: internal.Tprintf(scanHelp, map[string]any{
|
||||
"appName": id.Name,
|
||||
"command": "packages",
|
||||
}),
|
||||
|
||||
@@ -29,7 +29,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) {
|
||||
{
|
||||
name: "single non-expression error is retained",
|
||||
err: errors.New("foo"),
|
||||
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
|
||||
wantErr: func(t assert.TestingT, err error, i ...any) bool {
|
||||
return assert.Equal(t, "foo", err.Error())
|
||||
},
|
||||
wantHelp: "",
|
||||
@@ -42,7 +42,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) {
|
||||
err = multierror.Append(err, errors.New("bar"))
|
||||
return err
|
||||
}(),
|
||||
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
|
||||
wantErr: func(t assert.TestingT, err error, i ...any) bool {
|
||||
// note: this is the default formatting from the hashicorp multierror object
|
||||
expected := `2 errors occurred:
|
||||
* foo
|
||||
@@ -64,7 +64,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) {
|
||||
err = multierror.Append(err, errors.New("last"))
|
||||
return err
|
||||
}(),
|
||||
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
|
||||
wantErr: func(t assert.TestingT, err error, i ...any) bool {
|
||||
expected := `5 errors occurred:
|
||||
* foo
|
||||
* invalid expression: "foo": tags are not allowed with this operation (must use exact names)
|
||||
@@ -103,7 +103,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) {
|
||||
|
||||
return fmt.Errorf("top: %w", fmt.Errorf("middle: %w", err))
|
||||
}(),
|
||||
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
|
||||
wantErr: func(t assert.TestingT, err error, i ...any) bool {
|
||||
expected := `top: middle: 4 errors occurred:
|
||||
* foo: bar: last
|
||||
* invalid expression: "foo": tags are not allowed with this operation (must use exact names)
|
||||
@@ -142,7 +142,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) {
|
||||
// note we wrap the top error in a chain
|
||||
return fmt.Errorf("top: %w", fmt.Errorf("middle: %w", err))
|
||||
}(),
|
||||
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
|
||||
wantErr: func(t assert.TestingT, err error, i ...any) bool {
|
||||
expected := `top: middle: 4 errors occurred:
|
||||
* foo: bar: last
|
||||
* invalid expression: "foo": tags are not allowed with this operation (must use exact names)
|
||||
@@ -178,7 +178,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) {
|
||||
|
||||
return err
|
||||
}(),
|
||||
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
|
||||
wantErr: func(t assert.TestingT, err error, i ...any) bool {
|
||||
// note: the errors are removed and the help text shows the enriched error help
|
||||
expected := `2 errors occurred:
|
||||
* invalid expression: "foo": tags are not allowed with this operation (must use exact names)
|
||||
|
||||
@@ -92,7 +92,7 @@ func Scan(app clio.Application) *cobra.Command {
|
||||
Use: "scan [SOURCE]",
|
||||
Short: "Generate an SBOM",
|
||||
Long: "Generate a packaged-based Software Bill Of Materials (SBOM) from container images and filesystems",
|
||||
Example: internal.Tprintf(scanHelp, map[string]interface{}{
|
||||
Example: internal.Tprintf(scanHelp, map[string]any{
|
||||
"appName": id.Name,
|
||||
"command": "scan",
|
||||
}),
|
||||
|
||||
@@ -19,30 +19,30 @@ func Test_scanOptions_validateLegacyOptionsNotUsed(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "config file with no legacy options",
|
||||
cfg: "test-fixtures/scan-configs/no-legacy-options.yaml",
|
||||
cfg: "testdata/scan-configs/no-legacy-options.yaml",
|
||||
},
|
||||
{
|
||||
name: "config file with default image pull source legacy option",
|
||||
cfg: "test-fixtures/scan-configs/with-default-pull-source.yaml",
|
||||
cfg: "testdata/scan-configs/with-default-pull-source.yaml",
|
||||
wantErr: assertErrorContains("source.image.default-pull-source"),
|
||||
},
|
||||
{
|
||||
name: "config file with exclude-binary-overlap-by-ownership legacy option",
|
||||
cfg: "test-fixtures/scan-configs/with-exclude-binary-overlap-by-ownership.yaml",
|
||||
cfg: "testdata/scan-configs/with-exclude-binary-overlap-by-ownership.yaml",
|
||||
wantErr: assertErrorContains("package.exclude-binary-overlap-by-ownership"),
|
||||
},
|
||||
{
|
||||
name: "config file with file string legacy option",
|
||||
cfg: "test-fixtures/scan-configs/with-file-string.yaml",
|
||||
cfg: "testdata/scan-configs/with-file-string.yaml",
|
||||
wantErr: assertErrorContains("outputs"),
|
||||
},
|
||||
{
|
||||
name: "config file with file section",
|
||||
cfg: "test-fixtures/scan-configs/with-file-section.yaml",
|
||||
cfg: "testdata/scan-configs/with-file-section.yaml",
|
||||
},
|
||||
{
|
||||
name: "config file with base-path legacy option",
|
||||
cfg: "test-fixtures/scan-configs/with-base-path.yaml",
|
||||
cfg: "testdata/scan-configs/with-base-path.yaml",
|
||||
wantErr: assertErrorContains("source.base-path"),
|
||||
},
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func Test_scanOptions_validateLegacyOptionsNotUsed(t *testing.T) {
|
||||
}
|
||||
|
||||
func assertErrorContains(contains string) assert.ErrorAssertionFunc {
|
||||
return func(t assert.TestingT, err error, i ...interface{}) bool {
|
||||
return func(t assert.TestingT, err error, i ...any) bool {
|
||||
return assert.ErrorContains(t, err, contains, i...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func fetchLatestApplicationVersion(id clio.Identification) (*hashiVersion.Versio
|
||||
return nil, fmt.Errorf("HTTP %d on fetching latest version: %s", resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
versionBytes, err := io.ReadAll(resp.Body)
|
||||
versionBytes, err := io.ReadAll(io.LimitReader(resp.Body, 500))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read latest version: %w", err)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -313,10 +314,8 @@ func enrichmentEnabled(enrichDirectives []string, features ...string) *bool {
|
||||
directive = directive[1:]
|
||||
enable = false
|
||||
}
|
||||
for _, feature := range features {
|
||||
if directive == feature {
|
||||
return &enable
|
||||
}
|
||||
if slices.Contains(features, directive) {
|
||||
return &enable
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -122,7 +122,7 @@ func formatVersionOptions(nameVersionPairs []string) string {
|
||||
for _, name := range sortedAvailableFormats {
|
||||
s.WriteString("\n")
|
||||
|
||||
s.WriteString(fmt.Sprintf(" - %s", name))
|
||||
fmt.Fprintf(&s, " - %s", name)
|
||||
|
||||
if len(availableVersions[name]) > 0 {
|
||||
s.WriteString(" @ ")
|
||||
|
||||
@@ -32,7 +32,7 @@ func Test_MakeSBOMWriter(t *testing.T) {
|
||||
{
|
||||
name: "unknown format",
|
||||
outputs: []string{"unknown"},
|
||||
wantErr: func(t assert.TestingT, err error, bla ...interface{}) bool {
|
||||
wantErr: func(t assert.TestingT, err error, bla ...any) bool {
|
||||
return assert.ErrorContains(t, err, `unsupported output format "unknown", supported formats are:`)
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -125,7 +126,7 @@ func TestPkgCoverageImage(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPkgCoverageDirectory(t *testing.T) {
|
||||
sbom, _ := catalogDirectory(t, "test-fixtures/image-pkg-coverage")
|
||||
sbom, _ := catalogDirectory(t, "testdata/image-pkg-coverage")
|
||||
|
||||
observedLanguages := strset.New()
|
||||
definedLanguages := strset.New()
|
||||
@@ -194,11 +195,8 @@ func assertPackages(t *testing.T, sbom sbom.SBOM, test testCase, observedLanguag
|
||||
}
|
||||
|
||||
var foundLang bool
|
||||
for _, lang := range strings.Split(test.pkgLanguage.String(), ",") {
|
||||
if actualPkg.Language.String() == lang {
|
||||
foundLang = true
|
||||
break
|
||||
}
|
||||
if slices.Contains(strings.Split(test.pkgLanguage.String(), ","), actualPkg.Language.String()) {
|
||||
foundLang = true
|
||||
}
|
||||
if !foundLang {
|
||||
t.Errorf("bad language (pkg=%+v): %+v", actualPkg.Name, actualPkg.Language)
|
||||
@@ -261,7 +259,7 @@ func TestPkgCoverageImage_HasEvidence(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPkgCoverageDirectory_HasEvidence(t *testing.T) {
|
||||
sbom, _ := catalogDirectory(t, "test-fixtures/image-pkg-coverage")
|
||||
sbom, _ := catalogDirectory(t, "testdata/image-pkg-coverage")
|
||||
|
||||
var cases []testCase
|
||||
cases = append(cases, commonTestCases...)
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
func TestFileCataloging_Default(t *testing.T) {
|
||||
cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{})
|
||||
cfg = cfg.WithFilesConfig(filecataloging.DefaultConfig())
|
||||
sbom, _ := catalogDirectoryWithConfig(t, "test-fixtures/files", cfg)
|
||||
sbom, _ := catalogDirectoryWithConfig(t, "testdata/files", cfg)
|
||||
|
||||
var metadata map[file.Coordinates]file.Metadata
|
||||
|
||||
@@ -48,13 +48,13 @@ func TestFileCataloging_AllFiles(t *testing.T) {
|
||||
SkipFilesAboveSize: 30,
|
||||
},
|
||||
})
|
||||
sbom, _ := catalogDirectoryWithConfig(t, "test-fixtures/files", cfg)
|
||||
sbom, _ := catalogDirectoryWithConfig(t, "testdata/files", cfg)
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
|
||||
testPath := func(path string) string {
|
||||
return filepath.Join(pwd, "test-fixtures/files", path)
|
||||
return filepath.Join(pwd, "testdata/files", path)
|
||||
}
|
||||
|
||||
metadata := map[file.Coordinates]file.Metadata{
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNpmPackageLockDirectory(t *testing.T) {
|
||||
sbom, _ := catalogDirectory(t, "test-fixtures/npm-lock")
|
||||
sbom, _ := catalogDirectory(t, "testdata/npm-lock")
|
||||
|
||||
foundPackages := strset.New()
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestNpmPackageLockDirectory(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestYarnPackageLockDirectory(t *testing.T) {
|
||||
sbom, _ := catalogDirectory(t, "test-fixtures/yarn-lock")
|
||||
sbom, _ := catalogDirectory(t, "testdata/yarn-lock")
|
||||
|
||||
foundPackages := strset.New()
|
||||
// merge-objects and should-type are devDependencies in package.json and are excluded by default
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestBinaryElfRelationships(t *testing.T) {
|
||||
}
|
||||
|
||||
// run the test...
|
||||
sbom, _ := catalogFixtureImage(t, "elf-test-fixtures", source.SquashedScope)
|
||||
sbom, _ := catalogFixtureImage(t, "elf-testdata", source.SquashedScope)
|
||||
|
||||
// get a mapping of package names to their IDs
|
||||
nameToId := map[string]artifact.ID{}
|
||||
|
||||
@@ -278,7 +278,7 @@ func packageCatalogerExports(t *testing.T) map[string]exportTokenSet {
|
||||
if info.IsDir() ||
|
||||
!strings.HasSuffix(info.Name(), ".go") ||
|
||||
strings.HasSuffix(info.Name(), "_test.go") ||
|
||||
strings.Contains(path, "test-fixtures") ||
|
||||
strings.Contains(path, "testdata") ||
|
||||
strings.Contains(path, "internal") {
|
||||
return nil
|
||||
}
|
||||
@@ -329,7 +329,7 @@ func packageCatalogerExports(t *testing.T) map[string]exportTokenSet {
|
||||
}
|
||||
exportsPerPackage[pkg].Add(exportToken{
|
||||
Name: decl.Name.Name,
|
||||
Type: reflect.TypeOf(decl.Type).String(),
|
||||
Type: reflect.TypeFor[*ast.FuncType]().String(),
|
||||
SignatureSize: len(decl.Type.Params.List),
|
||||
ReturnTypeNames: returnTypes,
|
||||
})
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../../syft/pkg/cataloger/binary/test-fixtures/elf-test-fixtures
|
||||
-1
@@ -1 +0,0 @@
|
||||
See the syft/cataloger/java/test-fixtures/java-builds dir to generate test fixtures and copy to here manually.
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# we should strive to not commit blobs to the repo and strive to keep the build process of how blobs are acquired in-repo.
|
||||
# this blob is generated from syft/syft/catalogers/java/test-fixtures/java-builds , however, preserving the build process
|
||||
# this blob is generated from syft/syft/catalogers/java/testdata/java-builds , however, preserving the build process
|
||||
# twice in the repo seems redundant (even via symlink). Given that the fixture is a few kilobytes in size, the build process is already
|
||||
# captured, and integration tests should only be testing if jars can be discovered (not necessarily depth in java detection
|
||||
# functionality), committing it seems like an acceptable exception.
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../../../../syft/pkg/cataloger/binary/testdata/elf-testdata
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user