Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
115c3be05f | ||
|
|
d19588d87c | ||
|
|
f3a82307fe | ||
|
|
820c5ce485 | ||
|
|
b8e2bbc9cd | ||
|
|
0fedf7318f | ||
|
|
ae2702efaf | ||
|
|
cfcbc966ee | ||
|
|
cbfd0027ae | ||
|
|
7ab83002c8 | ||
|
|
e4d3fb6c73 |
@@ -1,4 +0,0 @@
|
||||
lib/
|
||||
dist/
|
||||
node_modules/
|
||||
coverage/
|
||||
83
.github/linters/.eslintrc.yml
vendored
83
.github/linters/.eslintrc.yml
vendored
@@ -1,83 +0,0 @@
|
||||
env:
|
||||
node: true
|
||||
es6: true
|
||||
jest: true
|
||||
|
||||
globals:
|
||||
Atomics: readonly
|
||||
SharedArrayBuffer: readonly
|
||||
|
||||
ignorePatterns:
|
||||
- '!.*'
|
||||
- '**/node_modules/.*'
|
||||
- '**/dist/.*'
|
||||
- '**/coverage/.*'
|
||||
- '*.json'
|
||||
|
||||
parser: '@typescript-eslint/parser'
|
||||
|
||||
parserOptions:
|
||||
ecmaVersion: 2023
|
||||
sourceType: module
|
||||
project:
|
||||
- './.github/linters/tsconfig.json'
|
||||
- './tsconfig.json'
|
||||
|
||||
plugins:
|
||||
- jest
|
||||
- '@typescript-eslint'
|
||||
|
||||
extends:
|
||||
- eslint:recommended
|
||||
- plugin:@typescript-eslint/eslint-recommended
|
||||
- plugin:@typescript-eslint/recommended
|
||||
- plugin:github/recommended
|
||||
- plugin:jest/recommended
|
||||
|
||||
rules:
|
||||
{
|
||||
'camelcase': 'off',
|
||||
'eslint-comments/no-use': 'off',
|
||||
'eslint-comments/no-unused-disable': 'off',
|
||||
'i18n-text/no-en': 'off',
|
||||
'import/no-namespace': 'off',
|
||||
'no-console': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'prettier/prettier': 'error',
|
||||
'semi': 'off',
|
||||
'@typescript-eslint/array-type': 'error',
|
||||
'@typescript-eslint/await-thenable': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': 'error',
|
||||
'@typescript-eslint/consistent-type-assertions': 'error',
|
||||
'@typescript-eslint/explicit-member-accessibility':
|
||||
['error', { 'accessibility': 'no-public' }],
|
||||
'@typescript-eslint/explicit-function-return-type':
|
||||
['error', { 'allowExpressions': true }],
|
||||
'@typescript-eslint/func-call-spacing': ['error', 'never'],
|
||||
'@typescript-eslint/no-array-constructor': 'error',
|
||||
'@typescript-eslint/no-empty-interface': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@typescript-eslint/no-extraneous-class': 'error',
|
||||
'@typescript-eslint/no-for-in-array': 'error',
|
||||
'@typescript-eslint/no-inferrable-types': 'error',
|
||||
'@typescript-eslint/no-misused-new': 'error',
|
||||
'@typescript-eslint/no-namespace': 'error',
|
||||
'@typescript-eslint/no-non-null-assertion': 'warn',
|
||||
'@typescript-eslint/no-require-imports': 'error',
|
||||
'@typescript-eslint/no-unnecessary-qualifier': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'@typescript-eslint/no-useless-constructor': 'error',
|
||||
'@typescript-eslint/no-var-requires': 'error',
|
||||
'@typescript-eslint/prefer-for-of': 'warn',
|
||||
'@typescript-eslint/prefer-function-type': 'warn',
|
||||
'@typescript-eslint/prefer-includes': 'error',
|
||||
'@typescript-eslint/prefer-string-starts-ends-with': 'error',
|
||||
'@typescript-eslint/promise-function-async': 'error',
|
||||
'@typescript-eslint/require-array-sort-compare': 'error',
|
||||
'@typescript-eslint/restrict-plus-operands': 'error',
|
||||
'@typescript-eslint/semi': ['error', 'never'],
|
||||
'@typescript-eslint/space-before-function-paren': 'off',
|
||||
'@typescript-eslint/type-annotation-spacing': 'error',
|
||||
'@typescript-eslint/unbound-method': 'error'
|
||||
}
|
||||
92
.github/linters/eslint.config.mjs
vendored
Normal file
92
.github/linters/eslint.config.mjs
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
import eslint from '@eslint/js'
|
||||
import importplugin from 'eslint-plugin-import'
|
||||
import jestplugin from 'eslint-plugin-jest'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default tseslint.config(
|
||||
// Ignore non-project files
|
||||
{
|
||||
name: 'ignore',
|
||||
ignores: ['.github', 'dist', 'coverage', '**/*.json', 'jest.setup.js']
|
||||
},
|
||||
// Use recommended rules from ESLint, TypeScript, and other plugins
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommendedTypeChecked,
|
||||
jestplugin.configs['flat/recommended'],
|
||||
importplugin.flatConfigs.recommended,
|
||||
importplugin.flatConfigs.typescript,
|
||||
// Override some rules
|
||||
{
|
||||
name: 'project-settings',
|
||||
languageOptions: {
|
||||
ecmaVersion: 2023,
|
||||
parserOptions: {
|
||||
project: ['./.github/linters/tsconfig.json', './tsconfig.json']
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
// eslint rules
|
||||
eqeqeq: ['error', 'smart'],
|
||||
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
|
||||
'no-console': 'off',
|
||||
'no-implicit-globals': 'error',
|
||||
'no-inner-declarations': 'error',
|
||||
'no-invalid-this': 'error',
|
||||
'no-return-assign': 'error',
|
||||
'no-sequences': 'error',
|
||||
'no-shadow': 'error',
|
||||
'no-useless-concat': 'error',
|
||||
'object-shorthand': ['error', 'always', { avoidQuotes: true }],
|
||||
'one-var': ['error', 'never'],
|
||||
'prefer-template': 'error',
|
||||
|
||||
// typescript-eslint rules
|
||||
'@typescript-eslint/array-type': 'error',
|
||||
'@typescript-eslint/consistent-type-assertions': 'error',
|
||||
'@typescript-eslint/explicit-function-return-type': [
|
||||
'error',
|
||||
{ allowExpressions: true }
|
||||
],
|
||||
'@typescript-eslint/explicit-member-accessibility': [
|
||||
'error',
|
||||
{ accessibility: 'no-public' }
|
||||
],
|
||||
'@typescript-eslint/no-extraneous-class': 'error',
|
||||
'@typescript-eslint/no-inferrable-types': 'error',
|
||||
'@typescript-eslint/no-non-null-assertion': 'warn',
|
||||
'@typescript-eslint/no-unnecessary-qualifier': 'error',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-useless-constructor': 'error',
|
||||
'@typescript-eslint/prefer-for-of': 'warn',
|
||||
'@typescript-eslint/prefer-function-type': 'warn',
|
||||
'@typescript-eslint/prefer-includes': 'error',
|
||||
'@typescript-eslint/prefer-string-starts-ends-with': 'error',
|
||||
'@typescript-eslint/promise-function-async': 'error',
|
||||
'@typescript-eslint/require-array-sort-compare': 'error',
|
||||
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||
|
||||
// eslint-plugin-import rules
|
||||
'import/extensions': 'error',
|
||||
'import/first': 'error',
|
||||
'import/no-absolute-path': 'error',
|
||||
'import/no-commonjs': 'error',
|
||||
'import/no-deprecated': 'warn',
|
||||
'import/no-dynamic-require': 'error',
|
||||
'import/no-extraneous-dependencies': 'error',
|
||||
'import/no-mutable-exports': 'error',
|
||||
'import/no-namespace': 'off',
|
||||
'import/no-unresolved': ['error', { ignore: ['csv-parse/sync'] }],
|
||||
'import/no-anonymous-default-export': [
|
||||
'error',
|
||||
{
|
||||
allowAnonymousClass: false,
|
||||
allowAnonymousFunction: false,
|
||||
allowArray: true,
|
||||
allowArrowFunction: false,
|
||||
allowLiteral: true,
|
||||
allowObject: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
70
README.md
70
README.md
@@ -24,6 +24,16 @@ CLI][7].
|
||||
See [Using artifact attestations to establish provenance for builds][11] for
|
||||
more information on artifact attestations.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
> [!NOTE]
|
||||
> Artifact attestations are available in public repositories for all
|
||||
> current GitHub plans. They are not available on legacy plans, such as Bronze,
|
||||
> Silver, or Gold. If you are on a GitHub Free, GitHub Pro, or GitHub Team plan,
|
||||
> artifact attestations are only available for public repositories. To use
|
||||
> artifact attestations in private or internal repositories, you must be on a
|
||||
> GitHub Enterprise Cloud plan.
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Usage
|
||||
|
||||
Within the GitHub Actions workflow which builds some artifact you would like to
|
||||
@@ -63,20 +73,25 @@ See [action.yml](action.yml)
|
||||
- uses: actions/attest-sbom@v2
|
||||
with:
|
||||
# Path to the artifact serving as the subject of the attestation. Must
|
||||
# specify exactly one of "subject-path" or "subject-digest". May contain a
|
||||
# glob pattern or list of paths (total subject count cannot exceed 1024).
|
||||
# specify exactly one of "subject-path", "subject-digest", or
|
||||
# "subject-checksums". May contain a glob pattern or list of paths
|
||||
# (total subject count cannot exceed 1024).
|
||||
subject-path:
|
||||
|
||||
# SHA256 digest of the subject for the attestation. Must be in the form
|
||||
# "sha256:hex_digest" (e.g. "sha256:abc123..."). Must specify exactly one
|
||||
# of "subject-path" or "subject-digest".
|
||||
# of "subject-path", "subject-digest", or "subject-checksums".
|
||||
subject-digest:
|
||||
|
||||
# Subject name as it should appear in the attestation. Required unless
|
||||
# "subject-path" is specified, in which case it will be inferred from the
|
||||
# path.
|
||||
# Subject name as it should appear in the attestation. Required when
|
||||
# identifying the subject with the "subject-digest" input.
|
||||
subject-name:
|
||||
|
||||
# Path to checksums file containing digest and name of subjects for
|
||||
# attestation. Must specify exactly one of "subject-path", "subject-digest",
|
||||
# or "subject-checksums".
|
||||
subject-checksums:
|
||||
|
||||
# Path to the JSON-formatted SBOM file to attest. File size cannot exceed
|
||||
# 16MB.
|
||||
sbom-path:
|
||||
@@ -99,9 +114,11 @@ See [action.yml](action.yml)
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
| Name | Description | Example |
|
||||
| ------------- | -------------------------------------------------------------- | ---------------------- |
|
||||
| `bundle-path` | Absolute path to the file containing the generated attestation | `/tmp/attestaion.json` |
|
||||
| Name | Description | Example |
|
||||
| ----------------- | -------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| `attestation-id` | GitHub ID for the attestation | `123456` |
|
||||
| `attestation-url` | URL for the attestation summary | `https://github.com/foo/bar/attestations/123456` |
|
||||
| `bundle-path` | Absolute path to the file containing the generated attestation | `/tmp/attestation.json` |
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
@@ -191,6 +208,41 @@ newline delimited list:
|
||||
dist/bar
|
||||
```
|
||||
|
||||
### Identify Subjects with Checksums File
|
||||
|
||||
If you are using tools like
|
||||
[goreleaser](https://goreleaser.com/customization/checksum/) or
|
||||
[jreleaser](https://jreleaser.org/guide/latest/reference/checksum.html) which
|
||||
generate a checksums file you can identify the attestation subjects by passing
|
||||
the path of the checksums file to the `subject-checksums` input. Each of the
|
||||
artifacts identified in the checksums file will be listed as a subject for the
|
||||
attestation.
|
||||
|
||||
```yaml
|
||||
- name: Calculate artifact digests
|
||||
run: |
|
||||
shasum -a 256 foo_0.0.1_* > subject.checksums.txt
|
||||
- uses: actions/attest-sbom@v2
|
||||
with:
|
||||
subject-checksums: subject.checksums.txt
|
||||
sbom-path: sbom.spdx.json
|
||||
```
|
||||
|
||||
<!-- markdownlint-disable MD038 -->
|
||||
|
||||
The file referenced by the `subject-checksums` input must conform to the same
|
||||
format used by the shasum tools. Each subject should be listed on a separate
|
||||
line including the hex-encoded digest (either SHA256 or SHA512), a space, a
|
||||
single character flag indicating either binary (`*`) or text (` `) input mode,
|
||||
and the filename.
|
||||
|
||||
<!-- markdownlint-enable MD038 -->
|
||||
|
||||
```text
|
||||
b569bf992b287f55d78bf8ee476497e9b7e9d2bf1c338860bfb905016218c740 foo_0.0.1_darwin_amd64
|
||||
a54fc515e616cac7fcf11a49d5c5ec9ec315948a5935c1e11dd610b834b14dde foo_0.0.1_darwin_arm64
|
||||
```
|
||||
|
||||
### Container Image
|
||||
|
||||
When working with container images you can invoke the action with the
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as main from '../src/main'
|
||||
const runMock = jest.spyOn(main, 'run').mockImplementation()
|
||||
|
||||
describe('index', () => {
|
||||
it('calls run when imported', async () => {
|
||||
it('calls run when imported', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
require('../src/index')
|
||||
|
||||
|
||||
27
action.yml
27
action.yml
@@ -9,20 +9,26 @@ inputs:
|
||||
subject-path:
|
||||
description: >
|
||||
Path to the artifact serving as the subject of the attestation. Must
|
||||
specify exactly one of "subject-path" or "subject-digest". May contain a
|
||||
glob pattern or list of paths (total subject count cannot exceed 1024).
|
||||
specify exactly one of "subject-path", "subject-digest", or
|
||||
"subject-checksums". May contain a glob pattern or list of paths (total
|
||||
subject count cannot exceed 1024).
|
||||
required: false
|
||||
subject-digest:
|
||||
description: >
|
||||
SHA256 digest of the subject for the attestation. Must be in the form
|
||||
"sha256:hex_digest" (e.g. "sha256:abc123..."). Must specify exactly one of
|
||||
"subject-path" or "subject-digest".
|
||||
"subject-path", "subject-digest", or "subject-checksums".
|
||||
required: false
|
||||
subject-name:
|
||||
description: >
|
||||
Subject name as it should appear in the attestation. Required unless
|
||||
"subject-path" is specified, in which case it will be inferred from the
|
||||
path.
|
||||
Subject name as it should appear in the attestation. Required when
|
||||
identifying the subject with the "subject-digest" input.
|
||||
subject-checksums:
|
||||
description: >
|
||||
Path to checksums file containing digest and name of subjects for
|
||||
attestation. Must specify exactly one of "subject-path", "subject-digest",
|
||||
or "subject-checksums".
|
||||
required: false
|
||||
sbom-path:
|
||||
description: >
|
||||
Path to the JSON-formatted SBOM file to attest. File size cannot exceed
|
||||
@@ -51,6 +57,12 @@ outputs:
|
||||
bundle-path:
|
||||
description: 'The path to the file containing the attestation bundle.'
|
||||
value: ${{ steps.attest.outputs.bundle-path }}
|
||||
attestation-id:
|
||||
description: 'The ID of the attestation.'
|
||||
value: ${{ steps.attest.outputs.attestation-id }}
|
||||
attestation-url:
|
||||
description: 'The URL for the attestation summary.'
|
||||
value: ${{ steps.attest.outputs.attestation-url }}
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
@@ -59,12 +71,13 @@ runs:
|
||||
id: generate-sbom-predicate
|
||||
with:
|
||||
sbom-path: ${{ inputs.sbom-path }}
|
||||
- uses: actions/attest@v2.0.1
|
||||
- uses: actions/attest@v2.2.0
|
||||
id: attest
|
||||
with:
|
||||
subject-path: ${{ inputs.subject-path }}
|
||||
subject-digest: ${{ inputs.subject-digest }}
|
||||
subject-name: ${{ inputs.subject-name }}
|
||||
subject-checksums: ${{ inputs.subject-checksums }}
|
||||
predicate-type:
|
||||
${{ steps.generate-sbom-predicate.outputs.predicate-type }}
|
||||
predicate-path:
|
||||
|
||||
3131
package-lock.json
generated
3131
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -28,7 +28,7 @@
|
||||
"ci-test": "jest",
|
||||
"format:write": "prettier --write **/*.ts",
|
||||
"format:check": "prettier --check **/*.ts",
|
||||
"lint:eslint": "npx eslint . -c ./.github/linters/.eslintrc.yml",
|
||||
"lint:eslint": "npx eslint . -c ./.github/linters/eslint.config.mjs",
|
||||
"lint:markdown": "npx markdownlint --config .github/linters/.markdown-lint.yml \"*.md\"",
|
||||
"lint": "npm run lint:eslint && npm run lint:markdown",
|
||||
"package": "ncc build src/index.ts --license licenses.txt",
|
||||
@@ -74,21 +74,18 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@actions/attest": "^1.5.0",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.10.1",
|
||||
"@typescript-eslint/eslint-plugin": "^7.17.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@types/node": "^22.10.7",
|
||||
"@vercel/ncc": "^0.38.3",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-github": "^5.1.3",
|
||||
"eslint-plugin-jest": "^28.9.0",
|
||||
"eslint-plugin-jsonc": "^2.18.2",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jest": "^28.11.0",
|
||||
"jest": "^29.7.0",
|
||||
"markdownlint-cli": "^0.43.0",
|
||||
"prettier": "^3.4.1",
|
||||
"prettier-eslint": "^16.3.0",
|
||||
"prettier": "^3.4.2",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.2"
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.20.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function parseSBOMFromPath(filePath: string): Promise<SBOM> {
|
||||
// Read the file content
|
||||
const fileContent = await fs.promises.readFile(filePath, 'utf8')
|
||||
|
||||
const sbom = JSON.parse(fileContent)
|
||||
const sbom = JSON.parse(fileContent) as object
|
||||
|
||||
if (checkIsSPDX(sbom)) {
|
||||
return { type: 'spdx', object: sbom }
|
||||
|
||||
Reference in New Issue
Block a user