├── .editorconfig
├── .eslintrc.js
├── .github
└── workflows
│ ├── ci.yml.skip
│ ├── conformance-run.yml.skip
│ ├── interoperability-report.yml.skip
│ ├── onboard-register.yml
│ ├── onboard-rotate.yml
│ ├── publish-editors-draft.yml
│ ├── publish-openapi-spec.yml
│ ├── publish-report-index.yml
│ ├── regression-did-web-discovery.yml.skip
│ └── regression-vc-jwt.yml.skip
├── .gitignore
├── .pr-preview.json
├── .prettierrc.js
├── AGENDA.md
├── CGFR
└── 2024-10-10
│ └── index.html
├── CODEOWNERS
├── CONTRIBUTING.md
├── LICENSE.md
├── MEETINGS.md
├── OPENAPI.md
├── README.md
├── docs
├── README.md
├── imported-collection.png
├── openapi
│ ├── index.html
│ ├── openapi.yml
│ ├── parameters
│ │ ├── _index.yml
│ │ ├── header
│ │ │ └── accept.yml
│ │ ├── path
│ │ │ ├── credential-id.yml
│ │ │ └── did.yml
│ │ └── query
│ │ │ └── limit.yml
│ ├── resources
│ │ ├── api-configuration.yml
│ │ ├── credential-issuer.yml
│ │ ├── credential-status.yml
│ │ ├── credential-verifier.yml
│ │ ├── credential.yml
│ │ ├── did.yml
│ │ ├── presentation-available.yml
│ │ ├── presentation-prover.yml
│ │ ├── presentation-submissions.yml
│ │ ├── presentation-verifier.yml
│ │ └── presentations.yml
│ ├── responses
│ │ ├── BadRequest.yml
│ │ ├── ErrInvalidDID.yml
│ │ ├── ErrUnknownIssuer.yml
│ │ ├── NotFound.yml
│ │ ├── NullResponse.yml
│ │ ├── Unauthenticated.yml
│ │ ├── Unauthorized.yml
│ │ ├── UnexpectedError.yml
│ │ └── _index.yml
│ └── schemas
│ │ ├── Credential.yml
│ │ ├── DidResolutionResponse.yml
│ │ ├── Error.yml
│ │ ├── Holder.yml
│ │ ├── IssueCredentialOptions.yml
│ │ ├── NotifyPresentationAvailableRequest.yml
│ │ ├── NotifyPresentationAvailableResponse.yml
│ │ ├── Presentation.yml
│ │ ├── PresentationOptions.yml
│ │ ├── SerializedVerifiableCredential.yml
│ │ ├── SerializedVerifiablePresentation.yml
│ │ ├── StatusListCredential.yml
│ │ ├── TraceabilityAPIDIDWebDocument.yml
│ │ ├── TraceablePresentation.yml
│ │ ├── VC-JWT.yml
│ │ ├── VP-JWT.yml
│ │ ├── VerifiableCredential.yml
│ │ ├── VerifiablePresentation.yml
│ │ ├── Verification.yml
│ │ ├── VerificationResult.yml
│ │ ├── Workflow.yml
│ │ └── _index.yml
├── reports
│ ├── .gitkeep
│ └── archive
│ │ └── index.html
├── spec
│ ├── index.html
│ ├── resources
│ │ ├── standards-stack.png
│ │ ├── workflow-def-ex.png
│ │ └── workflow-inst-ex.png
│ └── sections
│ │ ├── abstract.html
│ │ ├── api-spec.html
│ │ ├── authorization.html
│ │ ├── mandatory-to-implement-algorithms.html
│ │ ├── selective-disclosure.html
│ │ └── use-case-requirements.html
├── test-data
│ └── .gitkeep
├── tutorials
│ ├── .gitignore
│ ├── README.md
│ ├── authentication
│ │ ├── README.md
│ │ ├── authentication.postman_collection.json
│ │ ├── example.env
│ │ └── resources
│ │ │ ├── create-workspace.png
│ │ │ ├── environment-variables.png
│ │ │ ├── get-access-token-request.png
│ │ │ ├── get-access-token-response.png
│ │ │ └── get-access-token-tests.png
│ ├── credentials-status-update
│ │ ├── README.md
│ │ ├── credentials-status-update.postman_collection.json
│ │ └── resources
│ │ │ ├── credentials-status-update-auth.png
│ │ │ ├── credentials-status-update-body.png
│ │ │ ├── credentials-status-update-headers.png
│ │ │ ├── credentials-status-update-prereq.png
│ │ │ ├── credentials-status-update-tests-fail.png
│ │ │ ├── credentials-verification-response.png
│ │ │ ├── credentials-verification-tests-fail.png
│ │ │ └── select-environment.png
│ ├── did-web-discovery
│ │ ├── README.md
│ │ ├── did-web-discovery.postman_collection.json
│ │ ├── example.env
│ │ └── resources
│ │ │ ├── get-organization-dids-auth.png
│ │ │ ├── get-organization-dids-headers.png
│ │ │ ├── get-organization-dids-response.png
│ │ │ ├── get-organization-dids-tests-fail.png
│ │ │ ├── persist-access-token.png
│ │ │ └── select-environment.png
│ ├── interoperability_suite.postman_environment.json
│ ├── presentations-exchange-oauth
│ │ ├── README.md
│ │ ├── presentations-exchange-oauth.json
│ │ └── resources
│ │ │ ├── confirm-import.png
│ │ │ ├── import-button.png
│ │ │ ├── import-complete.png
│ │ │ └── import-from-link.png
│ ├── report-generation
│ │ ├── README.md
│ │ ├── build-index.js
│ │ ├── newman-json-sanitizer.js
│ │ └── report-tester.collection.json
│ ├── resources
│ │ ├── configure-environment.png
│ │ ├── create-workspace-details.png
│ │ ├── create-workspace-start.png
│ │ ├── import-collection-confirm.png
│ │ ├── import-collection-link.png
│ │ ├── import-environment-confirm.png
│ │ ├── import-environment-link.png
│ │ ├── import-start.png
│ │ └── select-environment.png
│ └── traceable-presentation-workflow
│ │ ├── README.md
│ │ └── traceable-presentation-workflow.postman_collection.json
└── weekly-minutes
│ ├── README.md
│ └── resources
│ ├── add-group-file-name.png
│ ├── add-group-file.png
│ ├── click-download-audio.png
│ ├── commit-group-file.png
│ ├── download-audio.png
│ ├── files-uploaded.png
│ ├── play-audio.png
│ ├── raw-irc-logs.png
│ ├── select-meeting.png
│ ├── upload-files-confirm.png
│ └── upload-files.png
├── environment-setup
├── README.md
├── create-pat.png
├── onboard-register.sh
├── onboard-rotate.sh
└── pubkey.asc
├── lerna.json
├── package-lock.json
├── package.json
├── reporting
├── README.md
├── assets
│ ├── conformance.j2
│ └── interoperability.j2
├── environment.yml
├── postman_reporter
│ ├── __init__.py
│ ├── report_charts.py
│ ├── report_config.py
│ ├── report_dashboard.py
│ ├── report_data.py
│ ├── report_static.py
│ └── reporter_util.py
├── reporter.py
└── requirements.txt
└── tests
├── README.md
├── conformance_suite.postman_collection.json
├── conformance_suite.postman_environment.json
├── resources
├── configure-environment.png
├── create-workspace-details.png
├── create-workspace-start.png
├── import-collection-confirm.png
├── import-collection-link.png
├── import-environment-confirm.png
├── import-environment-link.png
├── import-start.png
└── select-environment.png
├── traceability-v1.jsonld
├── update_conformance_schemas.sh
├── update_conformance_vcs.js
└── valid-credential.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | insert_final_newline = false
13 |
14 | [*.md]
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | commonjs: true,
5 | es2021: true,
6 | 'jest/globals': true,
7 | },
8 | plugins: ['jest', '@html-eslint'],
9 | extends: ['airbnb-base'],
10 | parserOptions: {
11 | ecmaVersion: 12,
12 | sourceType: 'module'
13 | },
14 | overrides: [
15 | {
16 | files: ['*.html'],
17 | parser: '@html-eslint/parser',
18 | extends: ['plugin:@html-eslint/recommended'],
19 | },
20 | ],
21 | settings: {
22 | 'html/report-bad-indent': 'error',
23 | },
24 | rules: {
25 | indent: 0,
26 | '@html-eslint/indent': ['error', 2],
27 | 'no-restricted-syntax': [0, 'ForOfStatement'],
28 | 'max-len': [2, 140],
29 | 'global-require': 0,
30 | 'no-console': 0,
31 | 'no-unused-vars': 0,
32 | 'comma-dangle': 0,
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml.skip:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - main
8 |
9 | jobs:
10 | postman:
11 | runs-on: ubuntu-latest
12 | # With the exception of GITHUB_TOKEN, secrets are not passed to the runner
13 | # when a workflow is triggered from a forked repository.
14 | if: "!contains(github.event.head_commit.message, '[skip ci]') && github.repository == github.event.repository.full_name"
15 |
16 | steps:
17 | - name: Check out git repository
18 | uses: actions/checkout@v2
19 |
20 | - name: Set up Node.js
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: 16.15.1
24 |
25 | - name: Install
26 | run: npm i
27 |
28 | - name: Lint
29 | run: npm run lint
30 |
--------------------------------------------------------------------------------
/.github/workflows/conformance-run.yml.skip:
--------------------------------------------------------------------------------
1 | name: Conformance Testing
2 |
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | # Every day at midnight
7 | - cron: '0 0 * * *'
8 |
9 | jobs:
10 |
11 | # conformance-run works through a matrix of actors and runs the conformance
12 | # test suite for each of them. Results are stored in a `reports` artifact for
13 | # later compilation and publishing.
14 | conformance-run:
15 | name: Run Conformance Suite
16 | runs-on: ubuntu-latest
17 | strategy:
18 | # Job must not stop iterating through matrix on failure
19 | fail-fast: false
20 | matrix:
21 | include:
22 | - name: "Mavennet"
23 | actor: "MAVENNET_STAGING"
24 | - name: "mesur.io"
25 | actor: "MESUR_IO_PRODUCTION"
26 | - name: "GS1US"
27 | actor: "GS1US"
28 | - name: 'BCGov'
29 | actor: 'BCGOV'
30 | steps:
31 | # Check out repo, set up node, and install dependencies.
32 | # @see https://github.com/actions/setup-node#usage
33 | - uses: actions/checkout@v3
34 | - uses: actions/setup-node@v3
35 | with:
36 | node-version: 16.15.1
37 | cache: 'npm'
38 | - run: npm ci
39 | - name: Run Tests
40 | env:
41 | organization_did_web: ${{secrets[format('{0}_ORGANIZATION_DID_WEB', matrix.actor)]}}
42 | client_id: ${{secrets[format('{0}_CLIENT_ID', matrix.actor)]}}
43 | client_secret: ${{secrets[format('{0}_CLIENT_SECRET', matrix.actor)]}}
44 | token_audience: ${{secrets[format('{0}_TOKEN_AUDIENCE', matrix.actor)]}}
45 | token_endpoint: ${{secrets[format('{0}_TOKEN_ENDPOINT', matrix.actor)]}}
46 | api_base_url: ${{secrets[format('{0}_API_BASE_URL', matrix.actor)]}}
47 | run: |
48 | npx newman run ./tests/conformance_suite.postman_collection.json \
49 | --env-var ORGANIZATION_DID_WEB=$organization_did_web \
50 | --env-var CLIENT_ID=$client_id \
51 | --env-var CLIENT_SECRET=$client_secret \
52 | --env-var TOKEN_AUDIENCE=$token_audience \
53 | --env-var TOKEN_ENDPOINT=$token_endpoint \
54 | --env-var API_BASE_URL=$api_base_url \
55 | --reporters cli,htmlextra,json \
56 | --reporter-htmlextra-skipSensitiveData \
57 | --reporter-htmlextra-export "newman/${{format('{0}-{1}-{2}.html', github.run_id, github.job, matrix.name)}}" \
58 | --reporter-json-export "newman/${{format('{0}-{1}-{2}.json', github.run_id, github.job, matrix.name)}}"
59 |
60 | # Write sanitized Newman output to `./docs/reports`.
61 | - name: Sanitize Report Output
62 | if: always() # Run even when postman tests fail
63 | run: npm run report:sanitize
64 |
65 | # Sanitized reports are needed by subsequent jobs
66 | - uses: actions/upload-artifact@v3
67 | if: always() # Run even when postman tests fail
68 | with:
69 | name: reports
70 | path: docs/reports/
71 |
72 | # conformance-compile compiles the sanitized raw report output into an
73 | # interactive HTML conformance report suitable for publishing.
74 | conformance-compile:
75 | name: Compile Reports
76 | runs-on: ubuntu-latest
77 |
78 | # Run even when postman tests fail
79 | if: always()
80 |
81 | # Wait for jobs which generate reporting input.
82 | needs:
83 | - conformance-run
84 |
85 | steps:
86 | # Check out repo, setup node, and install dependencies.
87 | # @see https://github.com/actions/setup-node#usage
88 | - uses: actions/checkout@v3
89 | - uses: actions/setup-node@v3
90 | with:
91 | node-version: 16.15.1
92 | cache: 'npm'
93 | - run: npm ci
94 |
95 | # Download 'reports' artifact
96 | - uses: actions/download-artifact@v3
97 | with:
98 | name: reports
99 | path: docs/reports/
100 |
101 | # Build report index
102 | - name: Build JSON Index
103 | run: npm run report:index -- --folder conformance
104 |
105 | # Set up Python 3.10
106 | - name: Set up Python 3.10
107 | uses: actions/setup-python@v4
108 | with:
109 | python-version: "3.10"
110 | cache: pip
111 | - run: pip install -r ./reporting/requirements.txt
112 |
113 | # Compile interactive report
114 | - name: Build Conformance Report
115 | working-directory: ./reporting
116 | run: ./reporter.py --mode ci --conformance
117 |
118 | # Compiled report must be added to artifact
119 | - uses: actions/upload-artifact@v3
120 | with:
121 | name: reports
122 | path: docs/reports/
123 |
124 | # conformance-publish publishes sanitized raw and interactive HTML reports to
125 | # the `reports/conformance` directory in GitHub pages. This job is restricted
126 | # to commits on the `main` branch to prevent feature branches from overwriting
127 | # production reports.
128 | conformance-publish:
129 | name: Publish Report
130 | runs-on: ubuntu-latest
131 |
132 | # Publishing must only happen when triggered on the 'main' branch to prevent
133 | # tests on other branches from polluting the published reports. Note that
134 | # `always()`` is a special flag that is REQUIRED in order to get this job to
135 | # run if jobs listed in the `needs:` section fail.
136 | if: github.ref == 'refs/heads/main' && always()
137 |
138 | # Report must be compiled before publishing
139 | needs:
140 | - conformance-compile
141 |
142 | steps:
143 | # Check out repo
144 | - uses: actions/checkout@v3
145 |
146 | # Download 'reports' artifact
147 | - uses: actions/download-artifact@v3
148 | with:
149 | name: reports
150 | path: docs/reports/
151 |
152 | # Publish report subfolder to GitHub Pages
153 | - name: Publish Conformance Report
154 | uses: peaceiris/actions-gh-pages@v3
155 | with:
156 | github_token: ${{ secrets.GITHUB_TOKEN }}
157 | publish_dir: ./docs/reports
158 | destination_dir: reports/conformance
159 |
160 | # Prepare an archive folder name and update the index.json appropriately
161 | - name: Prepare Conformance Archive
162 | id: archive
163 | run: |
164 | FOLDER=conformance-$(date +'%s')
165 | sed -i "s#reports/conformance/#reports/$FOLDER/#" ./docs/reports/index.json
166 | echo "::set-output name=folder::$FOLDER"
167 |
168 | # Publish report archive subfolder to GitHub Pages
169 | - name: Publish Conformance Archive
170 | uses: peaceiris/actions-gh-pages@v3
171 | with:
172 | github_token: ${{ secrets.GITHUB_TOKEN }}
173 | publish_dir: ./docs/reports
174 | destination_dir: reports/${{ steps.archive.outputs.folder }}
175 |
--------------------------------------------------------------------------------
/.github/workflows/onboard-register.yml:
--------------------------------------------------------------------------------
1 | # This workflow will ingest and parse a gpg-encrypted, base64-encoded secrets
2 | # file used for the test suite registration process.
3 | #
4 | # Prerequisites:
5 | # - Create a GitHub PAT token with `public_repo` scope
6 |
7 | name: "Onboard: Register"
8 |
9 | on:
10 | workflow_dispatch:
11 | inputs:
12 |
13 | # A GitHub PAT with `public_repo` scope is required in order to manage
14 | # the values in GitHub secrets.
15 | token:
16 | description: GitHub Token
17 | required: true
18 | type: string
19 |
20 | # This is a vendor-specific prefix to add to the secret names in the
21 | # provided file. This should be unique per vendor, and should include
22 | # the trailing underscore.
23 | prefix:
24 | description: Secret Prefix, e.g., 'VENDOR_SLUG_'
25 | required: true
26 | type: string
27 |
28 | # This is the base64-encoded GPG file provided by the organization that
29 | # is registering for the test suite.
30 | dotenv:
31 | description: Base64-encoded GPG file
32 | required: true
33 | type: string
34 |
35 | # Check this box to skip the step that prevents existing secrets from
36 | # being overwritten with new data.
37 | overwrite:
38 | description: Overwrite? (DANGER)
39 | required: false
40 | type: boolean
41 | default: false
42 |
43 | env:
44 | GITHUB_TOKEN: ${{ inputs.token }}
45 |
46 | jobs:
47 | onboard-register:
48 | runs-on: ubuntu-latest
49 | steps:
50 |
51 | # Import the GPG key from GitHub secrets into the gpg keyring on the
52 | # test runner. This is required in order to be able to decrypt secrets
53 | # files encrypted with the corresponding public key.
54 | - name: Import GPG Key
55 | run: echo -e '${{ env.PRIVATE_KEY }}' | gpg --import --batch --no-tty
56 | env:
57 | PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
58 |
59 | # To prevent formatting issues when maintainers paste the secrets file
60 | # into the workflow input, all data must be base64 encoded. This step
61 | # is able to handle both line-wrapped and un-wrapped `base64` output.
62 | # Once decoded, the file is passed to GPG to decrypt using the key that
63 | # was imported in the previous step and the passphrase from GitHub
64 | # secrets.
65 | - name: Decode Environment File
66 | run: |
67 | # Remove whitespace in case base64 is line-wrapped
68 | b64=$(echo '${{ inputs.dotenv }}' | tr -d "[:space:]")
69 |
70 | # Decoded dotenv may be binary or ASCII, store to disk
71 | echo $b64 | base64 -d > dotenv.gpg
72 |
73 | # Headless decryption of encrypted environment file with no recipient
74 | gpg --try-all-secrets --decrypt --pinentry-mode loopback \
75 | --passphrase '${{ env.PASSPHRASE }}' --output dotenv.asc dotenv.gpg
76 | env:
77 | PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
78 |
79 | # Ensure that secrets files created on Windows are properly updated to
80 | # convert CRLF line endings to LF to prevent corruption while reading
81 | # the file line-by-line
82 | - name: Convert Line Endings
83 | run: |
84 | sudo apt-get install -y dos2unix
85 | dos2unix dotenv.asc
86 |
87 | # By default, this workflow will fail if any of the keys in the secrets
88 | # file (prepended with the `prefix` input) already exist in GitHub secrets.
89 | # If you know what you are doing, you can disable this step by checking the
90 | # `Overwrite? (DANGER)` checkbox when running this workflow.
91 | - name: Check for Overwrites
92 | if: ${{ !inputs.overwrite }}
93 | run: |
94 | SECRETS=($(gh secret list --repo ${{github.repository}} | awk '{print $1}'))
95 |
96 | # Portion of line before '=' may not match an existing key
97 | while read -r LINE
98 | do
99 | SECRET_NAME=${{inputs.prefix}}${LINE%=*}
100 | if [[ " ${SECRETS[*]} " =~ " ${SECRET_NAME} " ]]
101 | then
102 | echo "Refusing to overwrite existing variable '${SECRET_NAME}'"
103 | exit 1
104 | fi
105 | done < dotenv.asc
106 |
107 | # This step parses keys and values from the decrypted secrets files, adds
108 | # the provided input `prefix` to the variable name, and stores everything
109 | # in GitHub secrets.
110 | - name: Set GitHub Secrets
111 | run: |
112 | while read -r LINE
113 | do
114 | SECRET_NAME=${{inputs.prefix}}${LINE%=*}
115 | SECRET_VALUE=${LINE#*=}
116 | gh secret set "${SECRET_NAME}" --body "${SECRET_VALUE}" \
117 | --repo ${{github.repository}}
118 | done < dotenv.asc
119 |
--------------------------------------------------------------------------------
/.github/workflows/onboard-rotate.yml:
--------------------------------------------------------------------------------
1 | # This workflow rotates the GPG key used to encrypt/decrypt secrets files used
2 | # for test suite registration process.
3 | #
4 | # Prerequisites:
5 | # - Create a GitHub PAT token with `public_repo` scope
6 |
7 | name: "Onboard: Rotate"
8 |
9 | on:
10 | workflow_dispatch:
11 | inputs:
12 |
13 | # A GitHub PAT with `public_repo` scope is required in order to manage
14 | # the values in GitHub secrets.
15 | token:
16 | description: GitHub Token
17 | required: true
18 | type: string
19 |
20 | env:
21 | GITHUB_TOKEN: ${{ inputs.token }}
22 |
23 | jobs:
24 | onboard-rotate:
25 | runs-on: ubuntu-latest
26 | steps:
27 |
28 | # Generate a GPG encryption key with a random passphrase. The key will
29 | # have a UID of `w3c-ccg/traceability-interop`.
30 | - name: Generate GPG Key
31 | id: gpg-generate
32 | run: |
33 | PASSPHRASE=$(gpg --gen-random --armor 1 32)
34 | echo "::add-mask::${PASSPHRASE}"
35 | cat <<- EOF | gpg --batch --generate-key
36 | Key-Type: RSA
37 | Key-Length: 4096
38 | Key-Usage: encrypt
39 | Name-Real: w3c-ccg/traceability-interop
40 | Name-Comment: test suite registration
41 | Passphrase: ${PASSPHRASE}
42 | Expire-Date: 0
43 | EOF
44 | echo "::set-output name=PASSPHRASE::$PASSPHRASE"
45 |
46 | # The key fingerprint is used to refer to the newly generated key in
47 | # subsequent commands. This limits the number of edits required if we
48 | # choose to change the UID.
49 | - name: Set GPG Fingerprint Output
50 | id: gpg-fingerprint
51 | run: |
52 | FINGERPRINT=$(gpg --with-colons --list-keys | awk -F: '/^pub/ { print $5 }')
53 | echo "::set-output name=FINGERPRINT::$FINGERPRINT"
54 |
55 | # Store the randomly generated passphrase and the secret key in GitHub
56 | # secrets. These will be retrieved and used to bootstrap the GPG agent
57 | # in the workflow that imports secrets for test suite registration.
58 | - name: Update Secrets
59 | run: |
60 | gh secret set 'GPG_PASSPHRASE' --body "${{env.PASSPHRASE}}" --repo ${{github.repository}}
61 | gpg --armor --pinentry-mode loopback --passphrase "${{ env.PASSPHRASE }}" --export-secret-key ${{ env.KEY_ID }} \
62 | | gh secret set 'GPG_PRIVATE_KEY' --repo ${{github.repository}}
63 | env:
64 | KEY_ID: ${{ steps.gpg-fingerprint.outputs.FINGERPRINT }}
65 | PASSPHRASE: ${{ steps.gpg-generate.outputs.PASSPHRASE }}
66 |
67 | # The public portion of the GPG key (ascii-armored) is exported so that
68 | # it can be accessed by end-users needing to encrypt secrets for test suite
69 | # registration.
70 | - uses: actions/checkout@v3
71 | - name: Update Public Key
72 | working-directory: ./environment-setup
73 | run: |
74 | gpg --armor --export ${{ env.KEY_ID }} > pubkey.asc
75 | env:
76 | KEY_ID: ${{ steps.gpg-fingerprint.outputs.FINGERPRINT }}
77 |
78 | # Create an automated git commit to add the exported ASCII public key
79 | # to the repository
80 | - name: Commit Key Changes
81 | working-directory: ./environment-setup
82 | run: |
83 | git config --global user.name ${GITHUB_ACTOR}
84 | git config --global user.email ${GITHUB_ACTOR}@users.noreply.github.com
85 | git add . # For first-time key creation
86 | git commit -am "chore: automated gpg key rotation"
87 | git push
88 |
--------------------------------------------------------------------------------
/.github/workflows/publish-editors-draft.yml:
--------------------------------------------------------------------------------
1 | name: Publish Editor's Draft
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - 'docs/spec/**'
9 |
10 | jobs:
11 | publish-editors-draft:
12 | runs-on: ubuntu-latest
13 | steps:
14 |
15 | # Check out repo, setup node, and install dependencies.
16 | # @see https://github.com/actions/setup-node#usage
17 | - uses: actions/checkout@v3
18 |
19 | # Publish editor's draft to GitHub Pages
20 | - uses: peaceiris/actions-gh-pages@v3
21 | with:
22 | github_token: ${{ secrets.GITHUB_TOKEN }}
23 | publish_dir: ./docs/spec
24 | destination_dir: draft
25 |
--------------------------------------------------------------------------------
/.github/workflows/publish-openapi-spec.yml:
--------------------------------------------------------------------------------
1 | name: OpenAPI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - 'docs/openapi/**'
9 |
10 | jobs:
11 | openapi-build:
12 | runs-on: ubuntu-latest
13 | steps:
14 |
15 | # Check out repo, setup node, and install dependencies.
16 | # @see https://github.com/actions/setup-node#usage
17 | - uses: actions/checkout@v3
18 | - uses: actions/setup-node@v3
19 | with:
20 | node-version: 16.15.1
21 | cache: 'npm'
22 | - run: npm ci
23 |
24 | # OpenAPI YAML must pass linting
25 | - name: Lint OpenAPI Specification YAML
26 | run: npm run validate-spec
27 |
28 | # Build the JSON version of the OpenAPI specification from the YAML source
29 | # files prior to publishing.
30 | - name: Build Open API Specification JSON
31 | run: npm run preserve
32 |
33 | # Publish openapi subfolder to GitHub Pages
34 | - name: Publish Open API Specification
35 | uses: peaceiris/actions-gh-pages@v3
36 | with:
37 | github_token: ${{ secrets.GITHUB_TOKEN }}
38 | publish_dir: ./docs/openapi
39 | destination_dir: openapi
40 |
41 |
--------------------------------------------------------------------------------
/.github/workflows/publish-report-index.yml:
--------------------------------------------------------------------------------
1 | name: Publish Report Index
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - 'docs/reports/archive/**'
9 |
10 | jobs:
11 | publish-index:
12 | runs-on: ubuntu-latest
13 | steps:
14 |
15 | # Check out repo, setup node, and install dependencies.
16 | # @see https://github.com/actions/setup-node#usage
17 | - uses: actions/checkout@v3
18 |
19 | # Publish reports/archive subfolder to GitHub Pages
20 | - name: Publish Open API Specification
21 | uses: peaceiris/actions-gh-pages@v3
22 | with:
23 | github_token: ${{ secrets.GITHUB_TOKEN }}
24 | publish_dir: ./docs/reports/archive
25 | destination_dir: reports/archive
26 |
--------------------------------------------------------------------------------
/.github/workflows/regression-did-web-discovery.yml.skip:
--------------------------------------------------------------------------------
1 | name: DID Web Discovery
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | unit-did-web-discovery:
8 | name: DID Web Discovery
9 | runs-on: ubuntu-latest
10 | strategy:
11 | fail-fast: false
12 | matrix:
13 | include:
14 | - name: "Mavennet"
15 | actor: "MAVENNET_STAGING"
16 | - name: "mesur.io"
17 | actor: "MESUR_IO_PRODUCTION"
18 | - name: "GS1US"
19 | actor: "GS1US"
20 | steps:
21 | # Check out repo, setup node, and install dependencies.
22 | # @see https://github.com/actions/setup-node#usage
23 | - uses: actions/checkout@v3
24 | - uses: actions/setup-node@v3
25 | with:
26 | node-version: 16.15.1
27 | cache: 'npm'
28 | - run: npm ci
29 | - name: Run Tests
30 | env:
31 | organization_did_web: ${{secrets[format('{0}_ORGANIZATION_DID_WEB', matrix.actor)]}}
32 | client_id: ${{secrets[format('{0}_CLIENT_ID', matrix.actor)]}}
33 | client_secret: ${{secrets[format('{0}_CLIENT_SECRET', matrix.actor)]}}
34 | token_audience: ${{secrets[format('{0}_TOKEN_AUDIENCE', matrix.actor)]}}
35 | token_endpoint: ${{secrets[format('{0}_TOKEN_ENDPOINT', matrix.actor)]}}
36 | api_base_url: ${{secrets[format('{0}_API_BASE_URL', matrix.actor)]}}
37 | run: |
38 | npx newman run ./docs/tutorials/did-web-discovery/did-web-discovery.postman_collection.json \
39 | --env-var ORGANIZATION_DID_WEB=$organization_did_web \
40 | --env-var CLIENT_ID=$client_id \
41 | --env-var CLIENT_SECRET=$client_secret \
42 | --env-var TOKEN_AUDIENCE=$token_audience \
43 | --env-var TOKEN_ENDPOINT=$token_endpoint \
44 | --env-var API_BASE_URL=$api_base_url \
45 | --reporters cli,htmlextra,json \
46 | --reporter-htmlextra-skipSensitiveData \
47 | --reporter-htmlextra-export "newman/${{format('{0}-{1}-{2}.html', github.run_id, github.job, matrix.name)}}" \
48 | --reporter-json-export "newman/${{format('{0}-{1}-{2}.json', github.run_id, github.job, matrix.name)}}"
49 |
50 | # Write sanitized Newman output to `./docs/reports`.
51 | - name: Sanitize Report Output
52 | if: always() # Run even when postman tests fail
53 | run: npm run report:sanitize
54 |
55 | # Sanitized reports are needed by subsequent jobs
56 | - uses: actions/upload-artifact@v3
57 | if: always() # Run even when postman tests fail
58 | with:
59 | name: reports
60 | path: docs/reports/
61 |
--------------------------------------------------------------------------------
/.github/workflows/regression-vc-jwt.yml.skip:
--------------------------------------------------------------------------------
1 | name: VC-JWT
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | strategy:
10 | # Matrix paths are independent, and failure for one provider should not
11 | # halt the running jobs testing another provider.
12 | fail-fast: false
13 | # See matrix of secrets...
14 | # https://sbulav.github.io/terraform/github-actions-matrix-secrets/
15 | matrix:
16 | include:
17 | - organization_did_web: MAVENNET_STAGING_ORGANIZATION_DID_WEB
18 | client_id: MAVENNET_STAGING_CLIENT_ID
19 | client_secret: MAVENNET_STAGING_CLIENT_SECRET
20 | token_audience: MAVENNET_STAGING_TOKEN_AUDIENCE
21 | token_endpoint: MAVENNET_STAGING_TOKEN_ENDPOINT
22 | api_base_url: MAVENNET_STAGING_API_BASE_URL
23 | - organization_did_web: MESUR_IO_PRODUCTION_ORGANIZATION_DID_WEB
24 | client_id: MESUR_IO_PRODUCTION_CLIENT_ID
25 | client_secret: MESUR_IO_PRODUCTION_CLIENT_SECRET
26 | token_audience: MESUR_IO_PRODUCTION_TOKEN_AUDIENCE
27 | token_endpoint: MESUR_IO_PRODUCTION_TOKEN_ENDPOINT
28 | api_base_url: MESUR_IO_PRODUCTION_API_BASE_URL
29 | - organization_did_web: GS1US_PRODUCTION_ORGANIZATION_DID_WEB
30 | client_id: GS1US_PRODUCTION_CLIENT_ID
31 | client_secret: GS1US_PRODUCTION_CLIENT_SECRET
32 | token_audience: GS1US_PRODUCTION_TOKEN_AUDIENCE
33 | token_endpoint: GS1US_PRODUCTION_TOKEN_ENDPOINT
34 | api_base_url: GS1US_PRODUCTION_API_BASE_URL
35 |
36 | steps:
37 | - name: Begin CI...
38 | uses: actions/checkout@v2
39 | - name: Use Node 16
40 | uses: actions/setup-node@v1
41 | with:
42 | node-version: 16.15.1
43 |
44 | - name: Run Tests
45 | env:
46 | organization_did_web: ${{secrets[matrix.organization_did_web]}}
47 | client_id: ${{secrets[matrix.client_id]}}
48 | client_secret: ${{secrets[matrix.client_secret]}}
49 | token_audience: ${{secrets[matrix.token_audience]}}
50 | token_endpoint: ${{secrets[matrix.token_endpoint]}}
51 | api_base_url: ${{secrets[matrix.api_base_url]}}
52 | run: |
53 | npx newman run ./docs/tutorials/vc-jwt/vc-jwt.collection.json \
54 | --env-var ORGANIZATION_DID_WEB=$organization_did_web \
55 | --env-var CLIENT_ID=$client_id \
56 | --env-var CLIENT_SECRET=$client_secret \
57 | --env-var TOKEN_AUDIENCE=$token_audience \
58 | --env-var TOKEN_ENDPOINT=$token_endpoint \
59 | --env-var API_BASE_URL=$api_base_url \
60 | --reporters cli,json
61 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # mac os
2 | .DS_Store
3 |
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 | lerna-debug.log*
11 | .pnpm-debug.log*
12 |
13 | # test runtime data
14 | test_data/**
15 | !test_data/.gitkeep
16 | newman
17 | __pycache__
18 |
19 | reporting/data/**
20 | reporting/html/**
21 |
22 | # Diagnostic reports (https://nodejs.org/api/report.html)
23 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
24 |
25 | # Runtime data
26 | pids
27 | *.pid
28 | *.seed
29 | *.pid.lock
30 |
31 | # Directory for instrumented libs generated by jscoverage/JSCover
32 | lib-cov
33 |
34 | # Coverage directory used by tools like istanbul
35 | coverage
36 | *.lcov
37 |
38 | # nyc test coverage
39 | .nyc_output
40 |
41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
42 | .grunt
43 |
44 | # Bower dependency directory (https://bower.io/)
45 | bower_components
46 |
47 | # node-waf configuration
48 | .lock-wscript
49 |
50 | # Compiled binary addons (https://nodejs.org/api/addons.html)
51 | build/Release
52 |
53 | # Dependency directories
54 | node_modules/
55 | jspm_packages/
56 |
57 | # Snowpack dependency directory (https://snowpack.dev/)
58 | web_modules/
59 |
60 | # TypeScript cache
61 | *.tsbuildinfo
62 |
63 | # Optional npm cache directory
64 | .npm
65 |
66 | # Optional eslint cache
67 | .eslintcache
68 |
69 | # Microbundle cache
70 | .rpt2_cache/
71 | .rts2_cache_cjs/
72 | .rts2_cache_es/
73 | .rts2_cache_umd/
74 |
75 | # Optional REPL history
76 | .node_repl_history
77 |
78 | # Output of 'npm pack'
79 | *.tgz
80 |
81 | # Yarn Integrity file
82 | .yarn-integrity
83 |
84 | # dotenv environment variables file
85 | .env
86 | .env.test
87 | .env.production
88 |
89 | # parcel-bundler cache (https://parceljs.org/)
90 | .cache
91 | .parcel-cache
92 |
93 | # Next.js build output
94 | .next
95 | out
96 |
97 | # Nuxt.js build / generate output
98 | .nuxt
99 | dist
100 |
101 | # Gatsby files
102 | .cache/
103 | # Comment in the public line in if your project uses Gatsby and not Next.js
104 | # https://nextjs.org/blog/next-9-1#public-directory-support
105 | # public
106 |
107 | # vuepress build output
108 | .vuepress/dist
109 |
110 | # Serverless directories
111 | .serverless/
112 |
113 | # FuseBox cache
114 | .fusebox/
115 |
116 | # DynamoDB Local files
117 | .dynamodb/
118 |
119 | # TernJS port file
120 | .tern-port
121 |
122 | # Stores VSCode versions used for testing VSCode extensions
123 | .vscode-test
124 |
125 | # yarn v2
126 | .yarn/cache
127 | .yarn/unplugged
128 | .yarn/build-state.yml
129 | .yarn/install-state.gz
130 | .pnp.*
131 |
132 | # OpenAPI JSON artifacts
133 | docs/openapi/openapi.json
134 |
135 |
136 | # Postman Reports
137 | # we actually do want to commit reports to source...
138 | # docs/reports
139 |
140 | .vscode
--------------------------------------------------------------------------------
/.pr-preview.json:
--------------------------------------------------------------------------------
1 | {
2 | "src_file": "docs/index.html",
3 | "type": "respec"
4 | }
5 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | tabWidth: 2,
3 | semi: true,
4 | singleQuote: true,
5 | printWidth: 120
6 | };
--------------------------------------------------------------------------------
/AGENDA.md:
--------------------------------------------------------------------------------
1 | # Open API for Interoperable Traceability
2 |
3 | The agenda may be updated periodically if a special topic is under discussion, or a guest speaker is identified, etc. In the event that the agenda is updated, the updated agenda will be distributed to the W3C CCG mailing list.
4 |
5 | 1. IP Note, Agenda Review, Scribe Selection (5 minutes)
6 |
7 | - Agenda Review (2 minutes)
8 |
9 | - IP Note: (1 minute)
10 |
11 | > Anyone can participate in these calls. However, all substantive contributors to any CCG Work Items must be members of the CCG with full IPR agreements signed. https://www.w3.org/community/credentials/join
12 |
13 | * Ensure you have a W3 account: https://www.w3.org/accounts/request
14 |
15 | * W3C COMMUNITY CONTRIBUTOR LICENSE AGREEMENT (CLA): https://www.w3.org/community/about/agreements/cla/
16 |
17 | - Call Notes (1 minute)
18 |
19 | - These minutes and an audio recording of everything said on this call are archived at https://w3c-ccg.github.io/meetings/
20 |
21 | - We use Jitsi text chat to queue speakers during the call as well as to take minutes.
22 |
23 | - All attendees should type “present+” to get your name on the attendee list in the transcript.
24 |
25 | - In IRC type “q+” to add yourself to the queue, with an optional reminder, e.g., “q+ to mention something”. The “to” is required.
26 |
27 | - If you’re not on chat, simply ask to be put on the queue.
28 |
29 | - Please be brief so the rest of the queue get a chance to chime in. You can always q+ again.
30 |
31 | - NOTE: This meeting is held by voice, not by text. Off-topic text comments are subject to deletion from the record. We work hard to manage a single thread of conversation so everyone can participate and be heard. Please respect the group process by joining the queue when you have something to contribute.
32 |
33 | - Scribe Selection (2 minutes) - We need a volunteer to scribe.
34 |
35 | 2. GitHub PR & Issue review
36 |
37 | * Review pull requests (PRs) in order (least recently updated first)
38 |
39 | For this portion of the meeting, address PRs in the focus repository first, followed by PRs in the other repository.
40 |
41 | * Publish link to sorted PRs in chat box —
42 | * [trace-interop](https://github.com/w3c-ccg/traceability-interop/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-asc) —
43 | ```pre
44 | https://github.com/w3c-ccg/traceability-interop/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-asc
45 | ```
46 | * [trace-vocab](https://github.com/w3c-ccg/traceability-vocab/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-asc) —
47 | ```pre
48 | https://github.com/w3c-ccg/traceability-vocab/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-asc
49 | ```
50 |
51 | * Publish link to each PR being discussed in chat box
52 |
53 | * Review issues in order (least recently updated first)
54 |
55 | For this portion of the meeting, address issues in the focus repository first, followed by issues in the other repository.
56 |
57 | * Publish link to sorted issues in chat box —
58 | * [trace-interop](https://github.com/w3c-ccg/traceability-interop/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc) —
59 | ```pre
60 | https://github.com/w3c-ccg/traceability-interop/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
61 | ```
62 | * [trace-vocab](https://github.com/w3c-ccg/traceability-vocab/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc) —
63 | ```pre
64 | https://github.com/w3c-ccg/traceability-vocab/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
65 | ```
66 |
67 | * Publish link to each issue being discussed in chat box
68 |
69 | 4. Proposals to Address Challenges
70 |
71 | 5. Next Steps
72 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These owners will be the default owners for everything in
2 | # the repo. Unless a later match takes precedence,
3 | # they will be requested for review when someone opens a
4 | # pull request.
5 | * @mkhraisha @nissimsan @brownoxford
6 |
7 | # See CODEOWNERS syntax here: https://help.github.com/articles/about-codeowners/#codeowners-syntax
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # W3C Credentials Community Group
2 |
3 | Contributions to this repository are intended to become part of
4 | Recommendation-track documents governed by the
5 | [W3C Patent Policy](https://www.w3.org/Consortium/Patent-Policy-20040205/) and
6 | [Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software).
7 | To make substantive contributions to specifications, you must either participate
8 | in the relevant W3C Working Group or make a non-member patent licensing commitment.
9 |
10 | If you are not the sole contributor to a contribution (pull request), please
11 | identify all contributors in the pull request comment.
12 |
13 | To add a contributor (other than yourself, that's automatic), mark them one
14 | per line as follows:
15 |
16 | ```
17 | +@github_username
18 | ```
19 |
20 | If you added a contributor by mistake, you can remove them in a comment with:
21 |
22 | ```
23 | -@github_username
24 | ```
25 |
26 | If you are making a pull request on behalf of someone else but you had no
27 | part in designing the feature, you can remove yourself with the above syntax.
28 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | All Reports in this Repository are licensed by Contributors under the [W3C Software and Document
2 | License](https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document).
3 |
4 | Contributions to Specifications are made under the
5 | [W3C CLA](https://www.w3.org/community/about/agreements/cla/).
6 |
7 | Contributions to Software, including sample implementations, are under the
8 | [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0).
--------------------------------------------------------------------------------
/MEETINGS.md:
--------------------------------------------------------------------------------
1 |
2 | ## Meetings
3 |
4 | Meetings are held:
5 |
6 | - Thursdays at 15:00 ET ([other timezones, accurate at time of viewing, which may vary with Daylight Saving changes](http://www.timebie.com/std/newyork.php?q=15))
7 | - Via [Jitsi](https://github.com/jitsi) in browser or
8 | [standalone app](https://github.com/jitsi/jitsi-meet-electron/releases)
9 | - using this link: [meet.w3c-ccg.org/traceability](https://meet.w3c-ccg.org/traceability)
10 | - With standing agenda to review open Pull Requests, oldest first
11 | ([trace-interop](https://github.com/w3c-ccg/traceability-interop/pulls?q=is%3Apr+is%3Aopen+sort%3Acreated-asc),
12 | [trace-vocab](https://github.com/w3c-ccg/traceability-vocab/pulls?q=is%3Apr+is%3Aopen+sort%3Acreated-asc)),
13 | then open Issues, least recentlyl updated first
14 | ([trace-interop](https://github.com/w3c-ccg/traceability-interop/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc),
15 | [trace-vocab](https://github.com/w3c-ccg/traceability-vocab/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc)),
16 | unless otherwise noted on the [mailing list](https://lists.w3.org/Archives/Public/public-credentials/)
17 |
18 | Historical archives for meetings [can be found here](https://github.com/w3c-ccg/meetings).
19 |
20 | ### Hosting instructions
21 |
22 | Any chair, editor, or other party authorized by CCG to manage recordings and
23 | minutes can do the following.
24 |
25 | #### Before the Meeting
26 |
27 | - Duplicate the
28 | [W3C-CCG Traceability Agenda Email Draft](https://docs.google.com/document/d/1Se_PIZNhIzZrwVftbYi-Z3oEMXvucQ7jNjxzjMVWCm4/edit)
29 | in Google Docs
30 | - Update all the items highlighted in yellow, in particular adding new agenda
31 | items for week starting with item 6.
32 | - If there are presentation materials, add them to the appropriate
33 | [dated meeting archives folder](https://github.com/w3c-ccg/meetings/)
34 | before the meeting.
35 | - Send agenda to public-credentials@w3.org before each meeting. Use the
36 | following format for the subject (modify date accordingly):
37 | ```
38 | [AGENDA] W3C CCG Traceability Call - 2022-11-22
39 | ```
40 | - Confirm in the
41 | [CCG mail archives](https://lists.w3.org/Archives/Public/public-credentials/)
42 | that the agenda was sent correctly
43 |
44 | #### During the Meeting
45 | - Be sure to click **`Start Recording`** and then **`Stop Subtitles`**
46 | - Read the IPR note
47 |
48 | > Anyone can participate in these calls. However, all substantive contributors to any CCG Work Items must be members of the CCG with full IPR agreements signed. Information about and links to the required license agreements can be found in the meeting agenda.
49 |
50 | - Make sure to link to the agenda at the beginning of the meeting (`Agenda: ...`)
51 | - Make sure the scribe is identified (`Scribe: ...` or `scribe+ ...`
52 | identifying someone else, or `scribe+` identifying oneself). Scribes, please
53 | familiarize yourself with general scribing guidance
54 | [here](https://www.w3.org/2008/04/scribe.html) and
55 | [here](https://www.w3.org/2008/xmlsec/Group/Scribe-Instructions.html).
56 | - Make sure topics are labeled when the topic changes (`Topic: ...`)
57 | - Make sure that action items are listed so that they can be added to issues
58 | later ("Action: ...")
59 |
60 | #### After the Meeting
61 | - Kick everyone from the meeting, and click **`Stop Recording`**
62 | - [Publish the minutes](https://github.com/w3c-ccg/traceability-interop/tree/main/docs/weekly-minutes)
63 |
64 | ## [Open API Specification](https://w3c-ccg.github.io/traceability-interop/)
65 |
66 | The spec contains documentation on use cases as well as required and optional
67 | API operations.
68 |
--------------------------------------------------------------------------------
/OPENAPI.md:
--------------------------------------------------------------------------------
1 | # OpenAPI Specification
2 |
3 | ## Importing the OpenAPI Specification Into Postman
4 |
5 | If you are using Postman, you can import all of the available API endpoints
6 | into an easy to use collection by following the instructions below:
7 |
8 | 1. While inside a Postman Workspace, you should see an **`import`** button at
9 | the top of your list of collections. Click this to begin the importing process.
10 | 2. After clicking **`import`**, a dialog will open providing you with a couple
11 | of options for importing the collection. The easiest is to import using a
12 | **`Link`**. To do this, simply paste the following URL into the input box,
13 | and click **`Import`**:
14 | `https://w3c-ccg.github.io/traceability-interop/openapi/openapi.json`.
15 | Alternatively, you can use the **`Raw text`** option by copying the JSON
16 | found at
17 | `https://w3c-ccg.github.io/traceability-interop/openapi/openapi.json`, and
18 | pasting it into the input box.
19 |
20 | You should see something like this in your collections once you have
21 | successfully imported the spec:
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | ## Included scripts for managing OpenAPI Specification
31 |
32 | 1. `npm run validate-spec`: This command can be used to validate the
33 | `openapi.yml` spec, ensuring there are no issues.
34 | 2. `npm run preserve`: This command is used to bundle our `openapi.yml` file
35 | into an `openapi.json` file that can be used to import the collection/spec.
36 |
37 | For additional documentation on how the `swagger-cli` can be used, visit
38 | [here](https://www.npmjs.com/package/swagger-cli).
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Traceability Interoperability Specification
2 |
3 | [](https://github.com/w3c-ccg/traceability-interop/actions/workflows/interoperability-report.yml)
4 | [](https://github.com/w3c-ccg/traceability-interop/actions/workflows/conformance-run.yml)
5 |
6 | ## About
7 |
8 | This specification describes an enterprise grade HTTP API for leveraging
9 | [W3C Decentralized Identifiers](https://www.w3.org/TR/did-core/) and
10 | [W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model/) with
11 | [W3C CCG Traceability Vocabulary](https://w3c-ccg.github.io/traceability-vocab/)
12 | and the [VC API](https://w3c-ccg.github.io/vc-api/) when possible.
13 |
14 | We encourage contributions meeting the [Contribution
15 | Guidelines](CONTRIBUTING.md). While we prefer the creation of
16 | [Issues](https://github.com/w3c-ccg/traceability-interop/issues) and
17 | [Pull Requests](https://github.com/w3c-ccg/traceability-interop/pulls) in the
18 | GitHub repository, discussions often occur on the
19 | [public-credentials](http://lists.w3.org/Archives/Public/public-credentials/)
20 | mailing list as well, and at regular public meetings ([see `MEETINGS.md`](./MEETINGS.md)).
21 |
22 | ## Latest Spec
23 |
24 | The current version of the specification can be found at [specification](https://w3id.org/traceability/interoperability/openapi)
25 |
26 | ## Traceability Interoperability
27 |
28 | - [Getting Started](#getting-started)
29 | - [Meetings and Hosting Instructions](./MEETINGS.md)
30 | - [Latest conformance test suite results](https://w3id.org/traceability/interoperability/reports/conformance)
31 | - [Latest interoperability test suite results](https://w3id.org/traceability/interoperability/reports/interoperability)
32 | - [Historical test suite result archive](https://w3id.org/traceability/interoperability/reports/archive)
33 |
34 | ## Getting Started
35 |
36 |
37 |
38 | - [To generate a report](./reporting/README.md)
39 | - [To import the OpenAPI specification into Postman](./OPENAPI.md)
40 | - For local development of the specification you will need to run the following:
41 | ```
42 | git clone git@github.com:w3c-ccg/traceability-interop.git
43 | cd traceability-interop
44 | npm i
45 | npm run serve
46 | ```
47 |
48 |
49 | ## Reference Implementation
50 |
51 | To simplify the creation of test vectors for the spec, we intend to provide
52 | a reference implementation.
53 |
54 | This implementation will cover all required AND optional APIs, and will be
55 | used to ensure no breaking changes are accidentally contributed to the spec.
56 |
57 | ## Postman Test Suites
58 |
59 | To ensure conformance and interoperability, tests are conducted in a manner
60 | consistent with production environments. We maintain a set of Postman
61 | collections and client credential configurations containing
62 | [conformance](./tests) and [interoperability](./docs/tutorials) test suites.
63 | These tests are executed via GitHub actions, on demand by implementers, and
64 | on a nightly scheduled basis. Please review the linked documentation for
65 | instructions on importing these test suites into your own local Postman
66 | environment.
67 |
68 | This approach allows us to test implementations in production with the
69 | appropriate security and authorization policies in place.
70 |
71 | If you would like to register an implementation to be tested against the test
72 | suite, please
73 | [review the step-by-step instructions provided here](./environment-setup/README.md).
74 |
75 | Test suite registration is required for participation in upcoming technical
76 | demonstrations with various government and non-government entities related to
77 | trade and import/export data exchange.
78 |
79 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | This directory is served by github pages
2 |
--------------------------------------------------------------------------------
/docs/imported-collection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/imported-collection.png
--------------------------------------------------------------------------------
/docs/openapi/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/docs/openapi/openapi.yml:
--------------------------------------------------------------------------------
1 | openapi: '3.0.0'
2 | info:
3 | version: 1.0.0
4 | title: Open API for Interoperable Traceability
5 | description: Identifier and Credentials APIs for DID.
6 | license:
7 | name: Apache 2.0
8 | url: https://www.apache.org/licenses/LICENSE-2.0.html
9 |
10 | servers:
11 | - url: https://api.did.actor
12 |
13 | tags:
14 | - name: Discovery
15 | - name: Identifiers
16 | - name: Credentials
17 | - name: Presentations
18 |
19 | paths:
20 | /did.json:
21 | $ref: './resources/api-configuration.yml'
22 |
23 | /identifiers/{did}:
24 | $ref: './resources/did.yml'
25 |
26 | /credentials/issue:
27 | $ref: './resources/credential-issuer.yml'
28 | /credentials/status:
29 | $ref: './resources/credential-status.yml'
30 | /credentials/verify:
31 | $ref: './resources/credential-verifier.yml'
32 | /credentials/{credential-id}:
33 | $ref: './resources/credential.yml'
34 |
35 | /presentations:
36 | $ref: './resources/presentations.yml'
37 | /presentations/prove:
38 | $ref: './resources/presentation-prover.yml'
39 | /presentations/verify:
40 | $ref: './resources/presentation-verifier.yml'
41 | /presentations/available:
42 | $ref: './resources/presentation-available.yml'
43 | /presentations/submissions:
44 | $ref: './resources/presentation-submissions.yml'
45 |
46 | components:
47 | securitySchemes:
48 | OAuth2:
49 | type: oauth2
50 | flows:
51 | clientCredentials:
52 | tokenUrl: https://example.com/oauth/token
53 | parameters:
54 | $ref: './parameters/_index.yml'
55 | schemas:
56 | $ref: './schemas/_index.yml'
57 | responses:
58 | $ref: './responses/_index.yml'
59 |
--------------------------------------------------------------------------------
/docs/openapi/parameters/_index.yml:
--------------------------------------------------------------------------------
1 | # path
2 | did:
3 | $ref: "./path/did.yml"
4 |
5 | # limit
6 | limit:
7 | $ref: "./query/limit.yml"
8 |
--------------------------------------------------------------------------------
/docs/openapi/parameters/header/accept.yml:
--------------------------------------------------------------------------------
1 | name: accept
2 | in: header
3 | required: true
4 | description: A verifiable credential format
5 | example: "application/vc+ld+json"
6 | schema:
7 | type: string
8 | enum: ["application/sd-jwt", "application/vc+ld+json"]
9 |
--------------------------------------------------------------------------------
/docs/openapi/parameters/path/credential-id.yml:
--------------------------------------------------------------------------------
1 | name: credential-id
2 | in: path
3 | required: true
4 | description: A verifiable credential id
5 | example: "810b3c74-4e80-420d-a8fe-7bde4c978e91"
6 | schema:
7 | type: string
8 |
--------------------------------------------------------------------------------
/docs/openapi/parameters/path/did.yml:
--------------------------------------------------------------------------------
1 | name: did
2 | in: path
3 | required: true
4 | description: A decentralized identifier
5 | schema:
6 | type: string
7 | example: "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn"
8 | # example: "did:web:api.did.actor:api"
9 |
--------------------------------------------------------------------------------
/docs/openapi/parameters/query/limit.yml:
--------------------------------------------------------------------------------
1 | name: limit
2 | in: query
3 | description: How many items to return at one time (max 100)
4 | required: false
5 | schema:
6 | type: integer
7 | format: int32
8 |
--------------------------------------------------------------------------------
/docs/openapi/resources/api-configuration.yml:
--------------------------------------------------------------------------------
1 | get:
2 | summary: API Configuration
3 | operationId: getTraceabilityAPIConfiguration
4 | tags:
5 | - Discovery
6 | responses:
7 | "200":
8 | description: Expected response to a valid request
9 | content:
10 | application/json:
11 | schema:
12 | $ref: "../schemas/TraceabilityAPIDIDWebDocument.yml"
13 | default:
14 | $ref: "../responses/UnexpectedError.yml"
15 |
--------------------------------------------------------------------------------
/docs/openapi/resources/credential-issuer.yml:
--------------------------------------------------------------------------------
1 | post:
2 | summary: Create
3 | operationId: issueCredential
4 | description: Issue a credential
5 | tags:
6 | - Credentials
7 | security:
8 | - OAuth2: []
9 | parameters:
10 | - $ref: "../parameters/header/accept.yml"
11 | requestBody:
12 | description: Parameters for issuing the credential.
13 | content:
14 | application/json:
15 | schema:
16 | type: object
17 | required:
18 | - credential
19 | - options
20 | properties:
21 | credential:
22 | $ref: '../schemas/Credential.yml'
23 | options:
24 | $ref: '../schemas/IssueCredentialOptions.yml'
25 |
26 | responses:
27 | '201':
28 | description: Resource Created
29 | content:
30 | application/json:
31 | schema:
32 | type: object
33 | required:
34 | - verifiableCredential
35 | properties:
36 | verifiableCredential:
37 | $ref: '../schemas/SerializedVerifiableCredential.yml'
38 | '400':
39 | $ref: '../responses/BadRequest.yml'
40 | '401':
41 | $ref: '../responses/Unauthenticated.yml'
42 | '403':
43 | $ref: '../responses/Unauthorized.yml'
44 | '422':
45 | description: Unknown Issuer
46 | content:
47 | application/json:
48 | schema:
49 | $ref: '../responses/ErrUnknownIssuer.yml'
50 | '500':
51 | $ref: '../responses/UnexpectedError.yml'
52 |
--------------------------------------------------------------------------------
/docs/openapi/resources/credential-status.yml:
--------------------------------------------------------------------------------
1 | post:
2 | summary: Update Status
3 | operationId: updateCredentialStatus
4 | description: Updates the status of an issued credential.
5 | tags:
6 | - Credentials
7 | security:
8 | - OAuth2: []
9 | requestBody:
10 | description: Parameters for updating the status of the issued credential.
11 | content:
12 | application/json:
13 | schema:
14 | type: object
15 | description: Request for updating the status of an issued credential.
16 | required:
17 | - credentialId
18 | - credentialStatus
19 | properties:
20 | credentialId:
21 | type: string
22 | credentialStatus:
23 | type: array
24 | maxItems: 1
25 | items:
26 | type: object
27 | required:
28 | - type
29 | - status
30 | properties:
31 | type:
32 | type: string
33 | enum: ['StatusList2021Entry']
34 | statusPurpose:
35 | type: string
36 | enum: ['revocation','suspension','status']
37 | # https://www.w3.org/TR/vc-status-list/
38 | # A value of `status` can be used to support multiple statuses, as described in the spec above.
39 | description: The value of `statusPurpose` should match the `statusPurpose` property on the StatusList2021Credential referred to by the credential being updated.
40 | status:
41 | # Traceability interoperability implementation must conform
42 | # with VC-API, which uses string for the status property.
43 | # https://w3c-ccg.github.io/vc-api/#update-status
44 | description: In the case of revocation or suspension status lists, use a string value of "1" (one) to indicate "revoked"/"suspended", or "0" (zero) to indicate otherwise.
45 | type: string
46 | enum: ['0', '1']
47 | example: {
48 | 'credentialId': 'urn:uuid:45a44711-e457-4fa8-9b89-69fe0287c86a',
49 | 'statusPurpose': 'revocation',
50 | # // https://w3c-ccg.github.io/vc-status-rl-2020/
51 | # // If the binary value of the position in the list is 1 (one),
52 | # // the verifiable credential is revoked, if it is 0 (zero) it is not revoked.
53 | 'credentialStatus': [{ 'type': 'StatusList2021Entry', 'status': '0' }],
54 | }
55 | responses:
56 | '200':
57 | description: Expected response to a valid request
58 | content:
59 | application/json:
60 | schema:
61 | type: object
62 | '400':
63 | $ref: '../responses/BadRequest.yml'
64 | '401':
65 | $ref: '../responses/Unauthenticated.yml'
66 | '403':
67 | $ref: '../responses/Unauthorized.yml'
68 | '404':
69 | $ref: '../responses/NotFound.yml'
70 | '500':
71 | $ref: '../responses/UnexpectedError.yml'
72 |
--------------------------------------------------------------------------------
/docs/openapi/resources/credential-verifier.yml:
--------------------------------------------------------------------------------
1 | post:
2 | summary: Verify
3 | operationId: verifyCredential
4 | description: Verify a credential
5 | tags:
6 | - Credentials
7 | security:
8 | - OAuth2: []
9 | parameters:
10 | - $ref: "../parameters/header/accept.yml"
11 | requestBody:
12 | description: Parameters for verifying a credential.
13 | content:
14 | application/json:
15 | schema:
16 | type: object
17 | required:
18 | - verifiableCredential
19 | properties:
20 | verifiableCredential:
21 | $ref: "../schemas/SerializedVerifiableCredential.yml"
22 |
23 | responses:
24 | "200":
25 | description: Expected response to a valid request
26 | content:
27 | application/json:
28 | schema:
29 | $ref: "../schemas/VerificationResult.yml"
30 | '400':
31 | $ref: '../responses/BadRequest.yml'
32 | '401':
33 | $ref: '../responses/Unauthenticated.yml'
34 | '403':
35 | $ref: '../responses/Unauthorized.yml'
36 | default:
37 | $ref: "../responses/UnexpectedError.yml"
38 |
--------------------------------------------------------------------------------
/docs/openapi/resources/credential.yml:
--------------------------------------------------------------------------------
1 |
2 | get:
3 | summary: Get Credential
4 | operationId: getCredentialById
5 | description: Get a verifiable credential by id. Required to make revocable credentials.
6 | tags:
7 | - Credentials
8 | security:
9 | - {}
10 | - OAuth2: []
11 | parameters:
12 | - $ref: "../parameters/path/credential-id.yml"
13 | responses:
14 | "200":
15 | description: Expected response to a valid request
16 | content:
17 | application/json:
18 | schema:
19 | $ref: "../schemas/StatusListCredential.yml"
20 | '401':
21 | $ref: '../responses/Unauthenticated.yml'
22 | '403':
23 | $ref: '../responses/Unauthorized.yml'
24 | '404':
25 | $ref: '../responses/NotFound.yml'
26 | default:
27 | $ref: "../responses/UnexpectedError.yml"
28 |
--------------------------------------------------------------------------------
/docs/openapi/resources/did.yml:
--------------------------------------------------------------------------------
1 | get:
2 | summary: Resolve
3 | operationId: resolve
4 | description: Get a DID's latest keys, services and capabilities
5 | tags:
6 | - Identifiers
7 | security:
8 | - OAuth2: []
9 | parameters:
10 | - $ref: "../parameters/path/did.yml"
11 | responses:
12 | "200":
13 | description: Expected response to a valid request
14 | content:
15 | application/json:
16 | schema:
17 | $ref: "../schemas/DidResolutionResponse.yml"
18 | "400":
19 | description: Bad Request
20 | content:
21 | application/json:
22 | schema:
23 | $ref: '../responses/ErrInvalidDID.yml'
24 | '401':
25 | $ref: '../responses/Unauthenticated.yml'
26 | '403':
27 | $ref: '../responses/Unauthorized.yml'
28 | "404":
29 | $ref: '../responses/NotFound.yml'
30 | default:
31 | $ref: "../responses/UnexpectedError.yml"
32 |
--------------------------------------------------------------------------------
/docs/openapi/resources/presentation-available.yml:
--------------------------------------------------------------------------------
1 | post:
2 | summary: Notify
3 | operationId: notifyPresentationAvailable
4 | description: Start a presentation exchange flow
5 | tags:
6 | - Presentations
7 | requestBody:
8 | description: Description of the flow
9 | content:
10 | application/json:
11 | schema:
12 | $ref: "../schemas/NotifyPresentationAvailableRequest.yml"
13 |
14 | responses:
15 | "200":
16 | description: Expected response to a valid request
17 | content:
18 | application/json:
19 | schema:
20 | $ref: "../schemas/NotifyPresentationAvailableResponse.yml"
21 | default:
22 | $ref: "../responses/UnexpectedError.yml"
23 |
--------------------------------------------------------------------------------
/docs/openapi/resources/presentation-prover.yml:
--------------------------------------------------------------------------------
1 | post:
2 | summary: Create
3 | operationId: provePresentation
4 | description: Create a presentation
5 | tags:
6 | - Presentations
7 | security:
8 | - OAuth2: []
9 | requestBody:
10 | description: Parameters for creating the presentation.
11 | content:
12 | application/json:
13 | schema:
14 | type: object
15 | properties:
16 | presentation:
17 | $ref: "../schemas/Presentation.yml"
18 | options:
19 | allOf:
20 | - $ref: "../schemas/PresentationOptions.yml"
21 | - type: object
22 | properties:
23 | type:
24 | type: string
25 | description: A linked data suite proof type
26 | enum: ["Ed25519Signature2018"]
27 | example: Ed25519Signature2018
28 | responses:
29 | "201":
30 | description: Expected response to a valid request
31 | content:
32 | application/json:
33 | schema:
34 | type: object
35 | required:
36 | - verifiablePresentation
37 | properties:
38 | verifiablePresentation:
39 | $ref: "../schemas/SerializedVerifiablePresentation.yml"
40 | '401':
41 | $ref: '../responses/Unauthenticated.yml'
42 | '403':
43 | $ref: '../responses/Unauthorized.yml'
44 | default:
45 | $ref: "../responses/UnexpectedError.yml"
46 |
--------------------------------------------------------------------------------
/docs/openapi/resources/presentation-submissions.yml:
--------------------------------------------------------------------------------
1 | post:
2 | summary: Submit
3 | operationId: storePresentation
4 | description: End a presentation exchange flow
5 | tags:
6 | - Presentations
7 | requestBody:
8 | description: A Verifiable Presentation to Store
9 | content:
10 | application/json:
11 | schema:
12 | $ref: "../schemas/VerifiablePresentation.yml"
13 |
14 | responses:
15 | "200":
16 | description: Expected response to a valid request
17 | content:
18 | application/json:
19 | schema:
20 | $ref: "../schemas/VerificationResult.yml"
21 | default:
22 | $ref: "../responses/UnexpectedError.yml"
23 |
--------------------------------------------------------------------------------
/docs/openapi/resources/presentation-verifier.yml:
--------------------------------------------------------------------------------
1 | post:
2 | summary: Verify
3 | operationId: verifyPresentation
4 | description: Verify a presentation
5 | tags:
6 | - Presentations
7 | security:
8 | - OAuth2: []
9 | requestBody:
10 | description: Parameters for verifying the presentation.
11 | content:
12 | application/json:
13 | schema:
14 | type: object
15 | properties:
16 | verifiablePresentation:
17 | $ref: "../schemas/SerializedVerifiablePresentation.yml"
18 | options:
19 | $ref: "../schemas/PresentationOptions.yml"
20 | responses:
21 | "200":
22 | description: Expected response to a valid request
23 | content:
24 | application/json:
25 | schema:
26 | $ref: "../schemas/VerificationResult.yml"
27 | '401':
28 | $ref: '../responses/Unauthenticated.yml'
29 | '403':
30 | $ref: '../responses/Unauthorized.yml'
31 | default:
32 | $ref: "../responses/UnexpectedError.yml"
33 |
--------------------------------------------------------------------------------
/docs/openapi/resources/presentations.yml:
--------------------------------------------------------------------------------
1 | post:
2 | summary: Present
3 | operationId: submitPresentationWithOAuth2Security
4 | description: >
5 | Create a presentation. This endpoint allows clients holding a valid OAuth2
6 | access token to create a presentation.
7 | tags:
8 | - Presentations
9 | security:
10 | - OAuth2: []
11 | requestBody:
12 | description: Description of the flow
13 | content:
14 | application/json:
15 | schema:
16 | $ref: '../schemas/TraceablePresentation.yml'
17 | responses:
18 | '200':
19 | description: Expected response to a valid request
20 | content:
21 | application/json:
22 | schema:
23 | type: object
24 | '401':
25 | $ref: '../responses/Unauthenticated.yml'
26 | '403':
27 | $ref: '../responses/Unauthorized.yml'
28 | default:
29 | $ref: '../responses/UnexpectedError.yml'
30 |
--------------------------------------------------------------------------------
/docs/openapi/responses/BadRequest.yml:
--------------------------------------------------------------------------------
1 | description: Bad Request
2 | content:
3 | application/json:
4 | schema:
5 | $ref: '../schemas/Error.yml'
6 |
--------------------------------------------------------------------------------
/docs/openapi/responses/ErrInvalidDID.yml:
--------------------------------------------------------------------------------
1 | description: |
2 | ErrInvalidDID is returned when the request path contains an invalid DID
3 | parameter.
4 | $ref: '../schemas/Error.yml'
5 |
--------------------------------------------------------------------------------
/docs/openapi/responses/ErrUnknownIssuer.yml:
--------------------------------------------------------------------------------
1 | description: |
2 | ErrUnknownIssuer is returned when the implementation does not have private
3 | key material for the requested `issuer`, and is therefore unable to issue
4 | the requested credential.
5 | $ref: '../schemas/Error.yml'
6 |
--------------------------------------------------------------------------------
/docs/openapi/responses/NotFound.yml:
--------------------------------------------------------------------------------
1 | description: Not Found
2 | content:
3 | application/json:
4 | schema:
5 | $ref: '../schemas/Error.yml'
6 |
--------------------------------------------------------------------------------
/docs/openapi/responses/NullResponse.yml:
--------------------------------------------------------------------------------
1 | description: Null response
2 |
--------------------------------------------------------------------------------
/docs/openapi/responses/Unauthenticated.yml:
--------------------------------------------------------------------------------
1 | description: Unauthorized
2 | content:
3 | application/json:
4 | schema:
5 | $ref: '../schemas/Error.yml'
6 |
--------------------------------------------------------------------------------
/docs/openapi/responses/Unauthorized.yml:
--------------------------------------------------------------------------------
1 | description: Forbidden
2 | content:
3 | application/json:
4 | schema:
5 | $ref: '../schemas/Error.yml'
6 |
--------------------------------------------------------------------------------
/docs/openapi/responses/UnexpectedError.yml:
--------------------------------------------------------------------------------
1 | description: Unexpected Error
2 | content:
3 | application/json:
4 | schema:
5 | $ref: '../schemas/Error.yml'
6 |
--------------------------------------------------------------------------------
/docs/openapi/responses/_index.yml:
--------------------------------------------------------------------------------
1 | BadRequest:
2 | $ref: './BadRequest.yml'
3 | UnexpectedError:
4 | $ref: './UnexpectedError.yml'
5 | NullResponse:
6 | $ref: './NullResponse.yml'
7 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/Credential.yml:
--------------------------------------------------------------------------------
1 | type: object
2 | required:
3 | - '@context'
4 | - type
5 | - issuer
6 | - issuanceDate
7 | - credentialSubject
8 | properties:
9 | '@context':
10 | description: |
11 | The JSON-LD Context defining all terms in the Credential. This array
12 | SHOULD contain "https://w3id.org/traceability/v1".
13 | type: array
14 | items:
15 | type: string
16 | id:
17 | description: The IRI identifying the Credential
18 | type: string
19 | type:
20 | description: The Type of the Credential
21 | type: array
22 | items:
23 | type: string
24 | minItems: 1
25 | issuer:
26 | description: This value MUST match the assertionMethod used to create the Verifiable Credential.
27 | oneOf:
28 | - type: string
29 | - type: object
30 | required:
31 | - id
32 | properties:
33 | id:
34 | description: The IRI identifying the Issuer
35 | type: string
36 | issuanceDate:
37 | description: This value MUST be an XML Date Time String
38 | type: string
39 | credentialSubject:
40 | type: object
41 | properties:
42 | id:
43 | description: The IRI identifying the Subject
44 | type: string
45 |
46 | example:
47 | {
48 | '@context': [
49 | 'https://www.w3.org/2018/credentials/v1',
50 | 'https://w3id.org/traceability/v1'
51 | ],
52 | 'id': 'urn:uuid:07aa969e-b40d-4c1b-ab46-ded252003ded',
53 | 'type': ['VerifiableCredential'],
54 | 'issuer': 'did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn',
55 | 'issuanceDate': '2010-01-01T19:23:24Z',
56 | 'credentialSubject': {
57 | 'id': 'did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn'
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/DidResolutionResponse.yml:
--------------------------------------------------------------------------------
1 | type: object
2 | required:
3 | - didDocument
4 | properties:
5 | didDocument:
6 | type: object
7 | required:
8 | - service
9 | properties:
10 | service:
11 | type: array
12 | minItems: 1
13 | items:
14 | type: object
15 | required:
16 | - type
17 | - serviceEndpoint
18 | properties:
19 | type:
20 | oneOf:
21 | - type: string
22 | - type: array
23 | items:
24 | type: string
25 | serviceEndpoint:
26 | type: string
27 | didResolutionMetadata:
28 | type: object
29 | didDocumentMetadata:
30 | type: object
31 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/Error.yml:
--------------------------------------------------------------------------------
1 | type: object
2 | required:
3 | - message
4 | properties:
5 | message:
6 | type: string
7 | details:
8 | oneOf:
9 | - type: string
10 | - type: array
11 | items:
12 | type: string
13 | - type: object
14 | additionalProperties: true
15 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/Holder.yml:
--------------------------------------------------------------------------------
1 | title: Holder
2 | type: object
3 | properties:
4 | id:
5 | type: string
6 | example:
7 | {
8 | "id": "did:web:sender.example.com"
9 | }
10 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/IssueCredentialOptions.yml:
--------------------------------------------------------------------------------
1 | title: Issue Credential Options
2 | type: object
3 | description: Options for issuing a verifiable credential
4 | required:
5 | - type
6 | properties:
7 | type:
8 | type: string
9 | description: The securing mechanism requested.
10 | enum: ['Ed25519Signature2018']
11 | created:
12 | type: string
13 | description: Date the proof was created. This value MUST be an XML Date Time String.
14 | credentialStatus:
15 | type: object
16 | description: The method of credential status.
17 | required:
18 | - type
19 | properties:
20 | type:
21 | type: string
22 | description: The type of credential status.
23 | enum: ['StatusList2021Entry']
24 | example:
25 | {
26 | 'type': 'Ed25519Signature2018',
27 | 'created': '2020-04-02T18:28:08Z',
28 | 'credentialStatus': { 'type': 'StatusList2021Entry' },
29 | }
30 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/NotifyPresentationAvailableRequest.yml:
--------------------------------------------------------------------------------
1 | title: Notify Presentation Available
2 | type: object
3 | properties:
4 | query:
5 | type: object
6 | description: See https://w3c-ccg.github.io/vp-request-spec/#format
7 | properties:
8 | type:
9 | type: string
10 | description: "The type of query the server should reply with."
11 | credentialQuery:
12 | type: object
13 | description: "Details of the client's available presentation"
14 | example:
15 | {
16 | "query":
17 | [
18 | {
19 | "type": "QueryByExample",
20 | "credentialQuery":
21 | [
22 | {
23 | "type": ["VerifiableCredential"],
24 | "reason": "We want to present credentials.",
25 | },
26 | ],
27 | },
28 | ],
29 | }
30 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/NotifyPresentationAvailableResponse.yml:
--------------------------------------------------------------------------------
1 | title: Notify Presentation Requirements
2 | type: object
3 | properties:
4 | query:
5 | type: object
6 | description: See https://w3c-ccg.github.io/vp-request-spec/#format
7 | domain:
8 | type: string
9 | description: See https://w3id.org/security#domain
10 | challenge:
11 | type: string
12 | description: See https://w3id.org/security#challenge
13 | example:
14 | {
15 | "query":
16 | [
17 | {
18 | "type": "QueryByExample",
19 | "credentialQuery":
20 | {
21 | "example":
22 | {
23 | "@context": ["https://www.w3.org/2018/credentials/v1"],
24 | "type": ["VerifiableCredential"],
25 | },
26 | },
27 | },
28 | ],
29 | "domain": "verifier.example.com",
30 | "challenge": "3182bdea-63d9-11ea-b6de-3b7c1404d57f",
31 | }
32 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/Presentation.yml:
--------------------------------------------------------------------------------
1 | title: Presentation
2 | type: object
3 | required:
4 | - '@context'
5 | - id
6 | - type
7 | properties:
8 | '@context':
9 | description: |
10 | The JSON-LD Context defining all terms in the Presentation. This array
11 | MUST contain "https://w3id.org/traceability/v1".
12 | type: array
13 | items:
14 | type: string
15 | id:
16 | type: string
17 | type:
18 | type: array
19 | items:
20 | type: string
21 | holder:
22 | type: string
23 | verifiableCredential:
24 | type: array
25 | items:
26 | $ref: './SerializedVerifiableCredential.yml'
27 |
28 | example:
29 | {
30 | '@context': [
31 | 'https://www.w3.org/2018/credentials/v1',
32 | 'https://w3id.org/traceability/v1'
33 | ],
34 | 'id': 'urn:uuid:48a46c8d-9313-45ec-a0be-7984a527223a',
35 | 'type': ['VerifiablePresentation'],
36 | 'holder': 'did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn',
37 | 'verifiableCredential':
38 | [
39 | {
40 | '@context': [
41 | 'https://www.w3.org/2018/credentials/v1',
42 | 'https://w3id.org/traceability/v1'
43 | ],
44 | 'id': 'urn:uuid:07aa969e-b40d-4c1b-ab46-ded252003ded',
45 | 'type': ['VerifiableCredential'],
46 | 'issuer': 'did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn',
47 | 'issuanceDate': '2010-01-01T19:23:24Z',
48 | 'credentialSubject': {
49 | 'id': 'did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn'
50 | },
51 | },
52 | ],
53 | }
54 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/PresentationOptions.yml:
--------------------------------------------------------------------------------
1 | title: Prove Presentation Options
2 | type: object
3 | description: Options for proving a verifiable presentation
4 | required:
5 | - challenge
6 | properties:
7 | domain:
8 | type: string
9 | example: "jobs.example"
10 | challenge:
11 | type: string
12 | example: "1f44d55f-f161-4938-a659-f8026467f126"
13 | example:
14 | {
15 | 'domain': 'api.did.actor',
16 | 'challenge': 'example'
17 | }
18 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/SerializedVerifiableCredential.yml:
--------------------------------------------------------------------------------
1 | title: Serialized Verifiable Credential
2 | oneOf:
3 | - allOf:
4 | - $ref: "./VerifiableCredential.yml"
5 | - type: object
6 | required:
7 | - id
8 | - $ref: "./VC-JWT.yml"
9 |
10 | example:
11 | {
12 | "@context": [
13 | "https://www.w3.org/2018/credentials/v1",
14 | "https://w3id.org/traceability/v1"
15 | ],
16 | "id": "urn:uuid:07aa969e-b40d-4c1b-ab46-ded252003ded",
17 | "type": ["VerifiableCredential"],
18 | "issuer": "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn",
19 | "issuanceDate": "2010-01-01T19:23:24Z",
20 | "credentialSubject": {
21 | "id": "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/SerializedVerifiablePresentation.yml:
--------------------------------------------------------------------------------
1 | title: Serialized Verifiable Presentation
2 | oneOf:
3 | - $ref: "./VerifiablePresentation.yml"
4 | - $ref: "./TraceablePresentation.yml"
5 | - $ref: "./VP-JWT.yml"
6 |
7 | example:
8 | {
9 | "@context":
10 | [
11 | "https://www.w3.org/2018/credentials/v1",
12 | "https://w3id.org/traceability/v1"
13 | ],
14 | "id": "urn:uuid:48a46c8d-9313-45ec-a0be-7984a527223a",
15 | "type": ["VerifiablePresentation"],
16 | "holder": "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn",
17 | "verifiableCredential":
18 | [
19 | {
20 | "@context":
21 | [
22 | "https://www.w3.org/2018/credentials/v1",
23 | "https://w3id.org/traceability/v1"
24 | ],
25 | "id": "urn:uuid:07aa969e-b40d-4c1b-ab46-ded252003ded",
26 | "type": ["VerifiableCredential"],
27 | "issuer": "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn",
28 | "issuanceDate": "2010-01-01T19:73:24Z",
29 | "credentialSubject": {
30 | "id": "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn"
31 | },
32 | },
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/StatusListCredential.yml:
--------------------------------------------------------------------------------
1 | title: Status List Verifiable Credential
2 | type: object
3 | allOf:
4 | - $ref: './Credential.yml'
5 | - type: object
6 | required:
7 | - id
8 | example:
9 | {
10 | "@context": [
11 | "https://www.w3.org/2018/credentials/v1",
12 | "https://w3id.org/vc/status-list/2021/v1"
13 | ],
14 | "credentialSubject": {
15 | "encodedList": "H4sIAAAAAAAA/2IYBaNgFIyCUTAKRsGIA4AAAAD//5666PEACAAA",
16 | "statusPurpose": "revocation",
17 | "statusSize": 1,
18 | "ttl": 5000,
19 | "type": "StatusList2021",
20 | "validFrom": "2023-06-19T23:31:48Z",
21 | "validUntil": "2023-06-20T23:31:48Z"
22 | },
23 | "id": "https://vendor.example/credentials/status-list/42",
24 | "issuanceDate": "2023-06-19T23:31:48Z",
25 | "issuer": "did:web:vendor.example",
26 | "type": [
27 | "VerifiableCredential",
28 | "StatusList2021Credential"
29 | ]
30 | }
--------------------------------------------------------------------------------
/docs/openapi/schemas/TraceabilityAPIDIDWebDocument.yml:
--------------------------------------------------------------------------------
1 | title: Traceability API DID Web Document
2 | type: object
3 | properties:
4 | '@context':
5 | oneOf:
6 | - type: string
7 | - type: array
8 | uniqueItems: true
9 | items:
10 | oneOf:
11 | - type: string
12 | - type: object
13 | id:
14 | type: string
15 | service:
16 | type: array
17 | items:
18 | type: object
19 | properties:
20 | id:
21 | type: string
22 | type:
23 | type: array
24 | items:
25 | type: string
26 | serviceEndpoint:
27 | type: string
28 |
29 | example:
30 | {
31 | "@context":
32 | [
33 | "https://www.w3.org/ns/did/v1",
34 | "https://w3id.org/traceability/v1",
35 | ],
36 | "id": "did:web:api.did.actor:api",
37 | "service":
38 | [
39 | {
40 | "id": "did:web:api.did.actor:api#traceability-api",
41 | "type": ["TraceabilityAPI"],
42 | "serviceEndpoint": "https://api.did.actor/api",
43 | },
44 | ],
45 | }
46 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/TraceablePresentation.yml:
--------------------------------------------------------------------------------
1 | title: Traceable Presentation
2 | type: object
3 | allOf:
4 | - $ref: "./VerifiablePresentation.yml"
5 | - type: object
6 | properties:
7 | holder:
8 | $ref: "./Holder.yml"
9 | workflow:
10 | $ref: "./Workflow.yml"
11 | example:
12 | {
13 | "verifiablePresentation": {
14 | "@context": [
15 | "https://www.w3.org/2018/credentials/v1",
16 | "https://w3id.org/traceability/v1"
17 | ],
18 | "type": [
19 | "VerifiablePresentation",
20 | "TraceablePresentation"
21 | ],
22 | "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5",
23 | "holder":{
24 | "id": "did:web:sender.example.com"
25 | },
26 | "workflow": {
27 | "definition": [
28 | "https://w3id.org/traceability#us-cbp-entry"
29 | ],
30 | "instance": [
31 | "urn:uuid:f5fb6ce4-b0b1-41b8-89b0-331ni58b7ee0"
32 | ],
33 | },
34 | "verifiableCredential": [
35 | {
36 | "@context": [
37 | "https://www.w3.org/2018/credentials/v1",
38 | "https://w3id.org/traceability/v1"
39 | ],
40 | "id": "urn:uuid:07aa969e-b40d-4c1b-ab46-ded252003ded",
41 | "type": ["VerifiableCredential"],
42 | "issuer": "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn",
43 | "issuanceDate": "2010-01-01T19:23:24Z",
44 | "credentialSubject": {
45 | "id": "urn:uuid:55a0a7e6-6140-47ab-8c6d-n155f403710c"
46 | }
47 | }
48 | ]
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/VC-JWT.yml:
--------------------------------------------------------------------------------
1 | title: VC JWT
2 | type: string
3 | example: "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa3RpU3pxRjlrcXdkVThWa2RCS3g1NkVZelhmcGduTlBVQUd6bnBpY05pV2ZuI3o2TWt0aVN6cUY5a3F3ZFU4VmtkQkt4NTZFWXpYZnBnbk5QVUFHem5waWNOaVdmbiJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWt0aVN6cUY5a3F3ZFU4VmtkQkt4NTZFWXpYZnBnbk5QVUFHem5waWNOaVdmbiIsInN1YiI6ImRpZDprZXk6ejZNa3RpU3pxRjlrcXdkVThWa2RCS3g1NkVZelhmcGduTlBVQUd6bnBpY05pV2ZuIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3czaWQub3JnL3NlY3VyaXR5L3N1aXRlcy9qd3MtMjAyMC92MSJdLCJpZCI6InVybjp1dWlkOjA3YWE5NjllLWI0MGQtNGMxYi1hYjQ2LWRlZDI1MjAwM2RlZCIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiZGlkOmtleTp6Nk1rdGlTenFGOWtxd2RVOFZrZEJLeDU2RVl6WGZwZ25OUFVBR3pucGljTmlXZm4iLCJpc3N1YW5jZURhdGUiOiIyMDEwLTAxLTAxVDE5OjIzOjI0WiIsImNyZWRlbnRpYWxTdWJqZWN0IjoiZGlkOmtleTp6Nk1rdGlTenFGOWtxd2RVOFZrZEJLeDU2RVl6WGZwZ25OUFVBR3pucGljTmlXZm4ifSwianRpIjoidXJuOnV1aWQ6MDdhYTk2OWUtYjQwZC00YzFiLWFiNDYtZGVkMjUyMDAzZGVkIiwibmJmIjoxMjYyMzczODA0fQ.ZXlKaGJHY2lPaUpGWkVSVFFTSXNJbUkyTkNJNlptRnNjMlVzSW1OeWFYUWlPbHNpWWpZMElsMTkuLlBUZ1N5UndTRmdRRmZRQXJRSkVfUm43c3cyNzJRZnhlTUZjYk16R05KZDRKVGtWS3d4a2p1UzRXQV9xTGdhM2NGYzRKd0JILXJPMk5haTFfRExsWEF3"
4 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/VP-JWT.yml:
--------------------------------------------------------------------------------
1 | title: VP JWT
2 | type: string
3 | example: "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa3RpU3pxRjlrcXdkVThWa2RCS3g1NkVZelhmcGduTlBVQUd6bnBpY05pV2ZuI3o2TWt0aVN6cUY5a3F3ZFU4VmtkQkt4NTZFWXpYZnBnbk5QVUFHem5waWNOaVdmbiJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWt0aVN6cUY5a3F3ZFU4VmtkQkt4NTZFWXpYZnBnbk5QVUFHem5waWNOaVdmbiIsInN1YiI6ImRpZDprZXk6ejZNa3RpU3pxRjlrcXdkVThWa2RCS3g1NkVZelhmcGduTlBVQUd6bnBpY05pV2ZuIiwidnAiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3czaWQub3JnL3NlY3VyaXR5L3N1aXRlcy9qd3MtMjAyMC92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVQcmVzZW50YXRpb24iXSwiaG9sZGVyIjoiZGlkOmtleTp6Nk1rdGlTenFGOWtxd2RVOFZrZEJLeDU2RVl6WGZwZ25OUFVBR3pucGljTmlXZm4iLCJ2ZXJpZmlhYmxlQ3JlZGVudGlhbCI6W3siQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDowN2FhOTY5ZS1iNDBkLTRjMWItYWI0Ni1kZWQyNTIwMDNkZWQiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIl0sImlzc3VlciI6ImRpZDprZXk6ejZNa3RpU3pxRjlrcXdkVThWa2RCS3g1NkVZelhmcGduTlBVQUd6bnBpY05pV2ZuIiwiaXNzdWFuY2VEYXRlIjoiMjAxMC0wMS0wMVQxOToyMzoyNFoiLCJjcmVkZW50aWFsU3ViamVjdCI6ImRpZDprZXk6ejZNa3RpU3pxRjlrcXdkVThWa2RCS3g1NkVZelhmcGduTlBVQUd6bnBpY05pV2ZuIiwicHJvb2YiOnsidHlwZSI6IkVkMjU1MTlTaWduYXR1cmUyMDE4IiwiY3JlYXRlZCI6IjIwMjEtMTAtMzBUMTk6MTY6MzBaIiwidmVyaWZpY2F0aW9uTWV0aG9kIjoiZGlkOmtleTp6Nk1rdGlTenFGOWtxd2RVOFZrZEJLeDU2RVl6WGZwZ25OUFVBR3pucGljTmlXZm4jejZNa3RpU3pxRjlrcXdkVThWa2RCS3g1NkVZelhmcGduTlBVQUd6bnBpY05pV2ZuIiwicHJvb2ZQdXJwb3NlIjoiYXNzZXJ0aW9uTWV0aG9kIiwiandzIjoiZXlKaGJHY2lPaUpGWkVSVFFTSXNJbUkyTkNJNlptRnNjMlVzSW1OeWFYUWlPbHNpWWpZMElsMTkuLnB1ZXRCWVMzcGtZbFl6QWVjQmlULVdraWdZQWxWYnNscno5d1BGbms5Slc0QXdqcnBKdmNzU2RaSlBoWnROeV9teU1KVU56Q19RYVl5dzNuaTFWMEJBIn19XX0sImF1ZCI6InN0cmluZyIsIm5vbmNlIjoiMWY0NGQ1NWYtZjE2MS00OTM4LWE2NTktZjgwMjY0NjdmMTI2In0.ZXlKaGJHY2lPaUpGWkVSVFFTSXNJbUkyTkNJNlptRnNjMlVzSW1OeWFYUWlPbHNpWWpZMElsMTkuLlcwT0dYSkVyT2xrSy1aSkxDR3Q1SWQ2WG9KYnZERGI2cGV2ZmhsblhWOW9CTWhQTTdhRFlBSmFRVFBKeG9neW4xd19MTHgzRHdnN3hvVGRwZllSTUJB"
4 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/VerifiableCredential.yml:
--------------------------------------------------------------------------------
1 | title: Verifiable Credential
2 | type: object
3 | allOf:
4 | - $ref: "./Credential.yml"
5 | - type: object
6 | example:
7 | {
8 | "@context": [
9 | "https://www.w3.org/2018/credentials/v1",
10 | "https://w3id.org/traceability/v1"
11 | ],
12 | "id": "urn:uuid:07aa969e-b40d-4c1b-ab46-ded252003ded",
13 | "type": ["VerifiableCredential"],
14 | "issuer": "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn",
15 | "issuanceDate": "2010-01-01T19:23:24Z",
16 | "credentialSubject": {
17 | "id": "did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/VerifiablePresentation.yml:
--------------------------------------------------------------------------------
1 | title: Verifiable Presentation
2 | type: object
3 | allOf:
4 | - $ref: "./Presentation.yml"
5 | - type: object
6 | example:
7 | {
8 | "verifiablePresentation": {
9 | "@context": [
10 | "https://www.w3.org/2018/credentials/v1"
11 | ],
12 | "holder": "did:web:vc.mesur.io:v1",
13 | "id": "urn:uuid:738c4139-4dea-412e-94b7-c31fd079247a",
14 | "type": "VerifiablePresentation",
15 | "verifiableCredential": [
16 | {
17 | "@context": [
18 | "https://www.w3.org/2018/credentials/v1",
19 | "https://w3id.org/vc/status-list/2021/v1"
20 | ],
21 | "credentialStatus": {
22 | "id": "https://vc.mesur.io/v1/credentials/status#9",
23 | "statusListCredential": "https://vc.mesur.io/v1/credentials/status",
24 | "statusListIndex": 9,
25 | "statusPurpose": "revocation",
26 | "type": "StatusList2021Entry"
27 | },
28 | "credentialSubject": {
29 | "id": "did:example:123"
30 | },
31 | "id": "urn:uuid:2569b762-e23c-475d-8f38-66ce813b4d17",
32 | "issuanceDate": "2023-06-19T23:16:57.945Z",
33 | "issuer": "did:web:vc.mesur.io:v1",
34 | "type": [
35 | "VerifiableCredential"
36 | ]
37 | }
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/Verification.yml:
--------------------------------------------------------------------------------
1 | title: Verification
2 | type: object
3 | properties:
4 | title:
5 | type: string
6 | enum:
7 | - Activation
8 | - Expired
9 | - Proof
10 | - Revocation
11 | - Signature
12 | status:
13 | type: string
14 | enum:
15 | - good
16 | - bad
17 | description:
18 | type: string
19 | required:
20 | - title
21 | - status
22 | example:
23 | {
24 | "title": "Activation",
25 | "status": "good",
26 | "description": "This credential activated 2 weeks ago"
27 | }
28 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/VerificationResult.yml:
--------------------------------------------------------------------------------
1 | title: Verification Result
2 | type: object
3 | properties:
4 | verified:
5 | type: boolean
6 | required:
7 | - verified
8 | additionalProperties: true
9 | example:
10 | {
11 | "verified": true
12 | }
13 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/Workflow.yml:
--------------------------------------------------------------------------------
1 | title: Workflow
2 | type: object
3 | properties:
4 | instance:
5 | type: array
6 | items:
7 | type: string
8 | definition:
9 | type: array
10 | items:
11 | type: string
12 | example:
13 | {
14 | "@context": ["https://w3id.org/traceability/v1"],
15 | "type": ["Workflow"],
16 | "workflow":
17 | {
18 | "instance": ["urn:uuid:f5fb6ce4-b0b1-41b8-89b0-331ni58b7ee0"],
19 | "definition": ["https://w3id.org/traceability#us-cbp-entry"],
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/docs/openapi/schemas/_index.yml:
--------------------------------------------------------------------------------
1 | Error:
2 | $ref: "./Error.yml"
3 |
--------------------------------------------------------------------------------
/docs/reports/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/reports/.gitkeep
--------------------------------------------------------------------------------
/docs/reports/archive/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/docs/spec/resources/standards-stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/spec/resources/standards-stack.png
--------------------------------------------------------------------------------
/docs/spec/resources/workflow-def-ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/spec/resources/workflow-def-ex.png
--------------------------------------------------------------------------------
/docs/spec/resources/workflow-inst-ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/spec/resources/workflow-inst-ex.png
--------------------------------------------------------------------------------
/docs/spec/sections/abstract.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Abstract
4 |
5 | This specification describes discovery and exchange mechanisms of [[[VC-DATA-MODEL]]] [[VC-DATA-MODEL]],
6 | particularly as they relate to supply chain use cases.
7 | Exchanged Verifiable Credentials often implement schemas defined in
8 | the [[[TRACE-VOCAB]]] [[TRACE-VOCAB]]..
9 |
10 |
11 | Using Verifiable Credentials to represent supply chain data enables interoperability between disparate actors,
12 | and provides the ability to cryptographically verify the authenticity of the data.
13 |
14 |
15 | This specification uses [[[DID-CORE]]] [[DID-CORE]]
16 | to identify organizations within a supply chain. This enables organizations to interact with parties
17 | outside their traditional supply chains, and removes the need for a central authority to identify supply chain
18 | organizations.
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/spec/sections/api-spec.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Services
4 |
5 | This section describes the HTTP services a conformant Traceability API MUST
6 | implement.
7 |
8 |
9 | See the Open API for Interoperable Traceability for the full API definition.
10 |
11 |
--------------------------------------------------------------------------------
/docs/spec/sections/authorization.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Authentication
4 | Implementations MUST support OAuth 2.0 Client Credentials based authentication.
5 |
6 |
7 | Client Credentials Grant is appropriate for verifying trusted application authorization for Internal/External APIs.
8 |
9 |
10 | See these links for more information on Machine to Machine API authorization:
11 |
12 |
28 |
29 |
30 | Presentation Authentication
31 |
32 | The following sequence of events is necessary for a Holder to present data to a Verifier:
33 |
34 |
35 |
36 | The Holder MUST authenticate by obtaining an
37 | access token through the client
38 | credentials flow, based on the client ID and client secret provided by the Verifier.
39 |
40 |
41 | Subsequent
42 | presentations MUST be made with the access token in the request header.
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/docs/spec/sections/mandatory-to-implement-algorithms.html:
--------------------------------------------------------------------------------
1 |
2 | Mandatory Algorithms
3 |
4 | The following digital signature algorithms
5 | MUST be implemented by conforming issuers and verifiers.
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/spec/sections/selective-disclosure.html:
--------------------------------------------------------------------------------
1 |
32 |
--------------------------------------------------------------------------------
/docs/test-data/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/test-data/.gitkeep
--------------------------------------------------------------------------------
/docs/tutorials/.gitignore:
--------------------------------------------------------------------------------
1 | *.env
2 | !example.env
3 | *.report.json
--------------------------------------------------------------------------------
/docs/tutorials/README.md:
--------------------------------------------------------------------------------
1 | # Traceability Interop Tutorials and Postman Tests
2 |
3 | This folder contains the postman tests and tutorials that are executed to demonstrate compliance with the specification.
4 |
5 | For a guided tutorial-like experience, please begin with the [authentication](./authentication/) tutorial.
6 |
7 | If you are already experienced with using Postman and would like to jump right in with the test suite, please continue reading.
8 |
9 | ## Importing The Test Suite
10 |
11 | ### Create a workspace
12 |
13 | Postman test suites are imported into workspaces. You may either choose an existing workspace before importing, or create a new one by opening the "Workspaces" dropdown menu at the top left of the Postman window and clicking on the "Create Workspace" button.
14 |
15 |
16 |
17 | In the following examples, the "Traceability Interoperability" workspace will be created and used.
18 |
19 |
20 |
21 | ### Import the collections
22 |
23 | This test suite contains several different collections to import (repeat the steps in this section for each item in the following list that you wish to import):
24 |
25 | - [Authentication Tutorial](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/authentication/authentication.postman_collection.json)
26 | - [DID Web Discovery Tutorial](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/did-web-discovery/did-web-discovery.postman_collection.json)
27 | - [Credentials Issue Tutorial](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/credentials-issue/credentials-issue.postman_collection.json)
28 | - [Credentials Verify Tutorial](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/credentials-verify/credentials-verify.postman_collection.json)
29 | - [Credentials Status Tutorial](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/credentials-status-update/credentials-status-update.postman_collection.json)
30 | - [Presentations Exchange Tutorial](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/presentations-exchange/presentations-exchange.postman_collection.json)
31 | - [Presentations Verify Tutorial](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/presentations-verify/presentations-verify.postman_collection.json)
32 | - [OAuth Presentations Exchange Tutorial](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/presentations-exchange-oauth/presentations-exchange-oauth.json)
33 | - [VC API - Suite Agility](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/agility/agility.collection.json)
34 | - [VC API - Issue and Verify Mill Test Report Certificate](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/mill-test-report-certificate/vc-api.mtrc.collection.json)
35 | - [VC API - VC-JWT Support](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/vc-jwt/vc-jwt.collection.json)
36 | - [Test Report Demo](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/report-generation/report-tester.collection.json)
37 | - [Workflow Instance Join](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/workflow-join/workflow-instance-join.collection.json)
38 |
39 | Use the "Import" button to begin importing the interoperability collections.
40 |
41 |
42 |
43 | When the import modal window opens, select the "Link" option, paste the link to the Postman collection in the text input, and click "Continue". (Links for the postman collections can be found at the beginning of this section.)
44 |
45 |
46 |
47 | After you click "Continue", Postman will download and process the remote url and present a confirmation screen. Click the "Import" button to continue.
48 |
49 |
50 |
51 | Repeat the steps in this section for each collection being imported.
52 |
53 | ### Import the environment
54 |
55 | Use the "Import" button again to import the interoperability environment.
56 |
57 |
58 |
59 | When the import modal window opens, select the "Link" option, paste the [link to the Postman environment](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/interoperability_suite.postman_environment.json) in the text input, and click "Continue"
60 |
61 |
62 |
63 | After you click "Continue", Postman will download and process the remote url and present a confirmation screen. Click the "Import" button to continue.
64 |
65 |
66 |
67 | ### Configure the environment
68 |
69 | Once the environment finishes importing, you will need to add in the values specific to your implementation. Click on the "Environments" tab, then highlight the "Traceability Interoperability" environment and update the first six values under the "INITIAL VALUE" column. Click "Reset All" to copy the values to the "CURRENT VALUE" column and then click "Save".
70 |
71 | __NOTE: Do not update the variables which start with `ISSUER_` or `VERIFIER_`. These reference the corresponding values from the first six variables and exist because production tests actually use two different providers for interoperability testing. When running locally, you will only have access to your own information, so interop tests will occur using a single implementation.__
72 |
73 |
74 |
75 | You are now ready to begin executing interoperability tests against your implementation!
76 |
--------------------------------------------------------------------------------
/docs/tutorials/authentication/authentication.postman_collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "_postman_id": "1e8344a6-a443-4ea9-b7bf-b22a79f51445",
4 | "name": "Authentication Tutorial",
5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6 | },
7 | "item": [
8 | {
9 | "name": "Get Access Token",
10 | "event": [
11 | {
12 | "listen": "test",
13 | "script": {
14 | "exec": [
15 | "// Token requests are expected to return a `200 Success` response code. Any",
16 | "// other response code should trigger a failure.",
17 | "pm.test(\"must return `200 Success` status\", function() {",
18 | " pm.response.to.have.status(200);",
19 | "})",
20 | "",
21 | "// The response should include an `access_token` value - this will be presented",
22 | "// to authenticated API endpoints in the `Authentication` header (see the last",
23 | "// testing code block for details on how this is persisted).",
24 | "pm.test(\"response body must include non-empty access_token\", function () {",
25 | " const { access_token } = pm.response.json()",
26 | " pm.expect(access_token).to.be.a('string').that.is.not.empty;",
27 | "});",
28 | "",
29 | "// The type of `access_token` returned by the token request is expected to be",
30 | "// `Bearer`.",
31 | "pm.test(\"response body must represent `Bearer` token\", function() {",
32 | " const { token_type } = pm.response.json()",
33 | " pm.expect(token_type).to.equal(\"Bearer\");",
34 | "});",
35 | "",
36 | "// The returned data includes an `expires_in` field that indicates time until",
37 | "// token expiration. Validate that this value is a whole number greater than",
38 | "// zero, as anything less than or equal to zero means that the `access_token`",
39 | "// is already expired.",
40 | "pm.test(\"returned token must expire in the future\", function() {",
41 | " const { expires_in } = pm.response.json()",
42 | " pm.expect(expires_in).to.be.above(0);",
43 | "});"
44 | ],
45 | "type": "text/javascript"
46 | }
47 | }
48 | ],
49 | "request": {
50 | "method": "POST",
51 | "header": [],
52 | "body": {
53 | "mode": "urlencoded",
54 | "urlencoded": [
55 | {
56 | "key": "audience",
57 | "value": "{{TOKEN_AUDIENCE}}",
58 | "type": "text"
59 | },
60 | {
61 | "key": "client_id",
62 | "value": "{{CLIENT_ID}}",
63 | "type": "text"
64 | },
65 | {
66 | "key": "client_secret",
67 | "value": "{{CLIENT_SECRET}}",
68 | "type": "text"
69 | },
70 | {
71 | "key": "grant_type",
72 | "value": "client_credentials",
73 | "type": "text"
74 | },
75 | {
76 | "key": "scope",
77 | "value": "{{CLIENT_SCOPE}}",
78 | "type": "text"
79 | }
80 | ]
81 | },
82 | "url": {
83 | "raw": "{{TOKEN_ENDPOINT}}",
84 | "host": [
85 | "{{TOKEN_ENDPOINT}}"
86 | ]
87 | }
88 | },
89 | "response": []
90 | }
91 | ],
92 | "event": [
93 | {
94 | "listen": "prerequest",
95 | "script": {
96 | "type": "text/javascript",
97 | "exec": [
98 | "pm.request.headers.add({key: 'User-Agent', value: 'W3C Traceability Interop Tests'});"
99 | ]
100 | }
101 | },
102 | {
103 | "listen": "test",
104 | "script": {
105 | "type": "text/javascript",
106 | "exec": [
107 | ""
108 | ]
109 | }
110 | }
111 | ],
112 | "variable": [
113 | {
114 | "key": "foo",
115 | "value": ""
116 | },
117 | {
118 | "key": "credential_issuer_id",
119 | "value": ""
120 | },
121 | {
122 | "key": "access_token",
123 | "value": ""
124 | }
125 | ]
126 | }
--------------------------------------------------------------------------------
/docs/tutorials/authentication/example.env:
--------------------------------------------------------------------------------
1 | CLIENT_ID=""
2 | CLIENT_SCOPE=""
3 | CLIENT_SECRET=""
4 | TOKEN_AUDIENCE=""
5 | TOKEN_ENDPOINT=""
6 |
--------------------------------------------------------------------------------
/docs/tutorials/authentication/resources/create-workspace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/authentication/resources/create-workspace.png
--------------------------------------------------------------------------------
/docs/tutorials/authentication/resources/environment-variables.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/authentication/resources/environment-variables.png
--------------------------------------------------------------------------------
/docs/tutorials/authentication/resources/get-access-token-request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/authentication/resources/get-access-token-request.png
--------------------------------------------------------------------------------
/docs/tutorials/authentication/resources/get-access-token-response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/authentication/resources/get-access-token-response.png
--------------------------------------------------------------------------------
/docs/tutorials/authentication/resources/get-access-token-tests.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/authentication/resources/get-access-token-tests.png
--------------------------------------------------------------------------------
/docs/tutorials/credentials-status-update/resources/credentials-status-update-auth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/credentials-status-update/resources/credentials-status-update-auth.png
--------------------------------------------------------------------------------
/docs/tutorials/credentials-status-update/resources/credentials-status-update-body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/credentials-status-update/resources/credentials-status-update-body.png
--------------------------------------------------------------------------------
/docs/tutorials/credentials-status-update/resources/credentials-status-update-headers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/credentials-status-update/resources/credentials-status-update-headers.png
--------------------------------------------------------------------------------
/docs/tutorials/credentials-status-update/resources/credentials-status-update-prereq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/credentials-status-update/resources/credentials-status-update-prereq.png
--------------------------------------------------------------------------------
/docs/tutorials/credentials-status-update/resources/credentials-status-update-tests-fail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/credentials-status-update/resources/credentials-status-update-tests-fail.png
--------------------------------------------------------------------------------
/docs/tutorials/credentials-status-update/resources/credentials-verification-response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/credentials-status-update/resources/credentials-verification-response.png
--------------------------------------------------------------------------------
/docs/tutorials/credentials-status-update/resources/credentials-verification-tests-fail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/credentials-status-update/resources/credentials-verification-tests-fail.png
--------------------------------------------------------------------------------
/docs/tutorials/credentials-status-update/resources/select-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/credentials-status-update/resources/select-environment.png
--------------------------------------------------------------------------------
/docs/tutorials/did-web-discovery/did-web-discovery.postman_collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "_postman_id": "7573cc79-8d9a-4dfd-8b2e-1c4079752653",
4 | "name": "DID Web Discovery Tutorial",
5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6 | },
7 | "item": [
8 | {
9 | "name": "Get Access Token",
10 | "event": [
11 | {
12 | "listen": "test",
13 | "script": {
14 | "exec": [
15 | "// Token requests are expected to return a `200 Success` response code. Any",
16 | "// other response code should trigger a failure.",
17 | "pm.test(\"must return `200 Success` status\", function() {",
18 | " pm.response.to.have.status(200);",
19 | "})",
20 | "",
21 | "// The response should include an `access_token` value - this will be presented",
22 | "// to authenticated API endpoints in the `Authentication` header (see the last",
23 | "// testing code block for details on how this is persisted).",
24 | "pm.test(\"response body must include non-empty access_token\", function () {",
25 | " const { access_token } = pm.response.json()",
26 | " pm.expect(access_token).to.be.a('string').that.is.not.empty;",
27 | "});",
28 | "",
29 | "// The type of `access_token` returned by the token request is expected to be",
30 | "// `Bearer`.",
31 | "pm.test(\"response body must represent `Bearer` token\", function() {",
32 | " const { token_type } = pm.response.json()",
33 | " pm.expect(token_type).to.equal(\"Bearer\");",
34 | "});",
35 | "",
36 | "// The returned data includes an `expires_in` field that indicates time until",
37 | "// token expiration. Validate that this value is a whole number greater than",
38 | "// zero, as anything less than or equal to zero means that the `access_token`",
39 | "// is already expired.",
40 | "pm.test(\"returned token must expire in the future\", function() {",
41 | " const { expires_in } = pm.response.json()",
42 | " pm.expect(expires_in).to.be.above(0);",
43 | "});",
44 | "",
45 | "// The returned `access_token` value is persisted as a Postman collection",
46 | "// variable that can be accessed by other requests in the collection by calling",
47 | "// `pm.collectionVariables.get(\"access_token\")`.",
48 | "pm.test(\"`access_token` persisted to collectionVariables\", function() {",
49 | " const { access_token } = pm.response.json()",
50 | " pm.collectionVariables.set(\"access_token\", access_token);",
51 | "});"
52 | ],
53 | "type": "text/javascript"
54 | }
55 | }
56 | ],
57 | "request": {
58 | "method": "POST",
59 | "header": [],
60 | "body": {
61 | "mode": "urlencoded",
62 | "urlencoded": [
63 | {
64 | "key": "audience",
65 | "value": "{{TOKEN_AUDIENCE}}",
66 | "type": "text"
67 | },
68 | {
69 | "key": "client_id",
70 | "value": "{{CLIENT_ID}}",
71 | "type": "text"
72 | },
73 | {
74 | "key": "client_secret",
75 | "value": "{{CLIENT_SECRET}}",
76 | "type": "text"
77 | },
78 | {
79 | "key": "grant_type",
80 | "value": "client_credentials",
81 | "type": "text"
82 | },
83 | {
84 | "key": "scope",
85 | "value": "{{CLIENT_SCOPE}}",
86 | "type": "text"
87 | }
88 | ]
89 | },
90 | "url": {
91 | "raw": "{{TOKEN_ENDPOINT}}",
92 | "host": [
93 | "{{TOKEN_ENDPOINT}}"
94 | ]
95 | }
96 | },
97 | "response": []
98 | },
99 | {
100 | "name": "Get Organization DIDs",
101 | "event": [
102 | {
103 | "listen": "test",
104 | "script": {
105 | "exec": [
106 | "pm.test(\"Status code is 200\", function () {",
107 | " pm.response.to.have.status(200);",
108 | "});",
109 | "",
110 | "pm.test(\"must include valid JSON response body\", function() {",
111 | " pm.response.json(); // will throw on parse failure",
112 | "});",
113 | "",
114 | "// The response JSON must include a didDocument property that contains the",
115 | "// resolved DID document.",
116 | "pm.test(\"didDocument must be present in response body\", function() {",
117 | " const jsonData = pm.response.json();",
118 | " pm.expect(jsonData).to.have.property('didDocument');",
119 | "});",
120 | "",
121 | "// Service array is used to look up traceability API service endpoint",
122 | "pm.test(\"Response must include 'service' array\", function() {",
123 | " const { service } = pm.response.json().didDocument;",
124 | " pm.expect(service).to.be.an('array').that.is.not.empty;",
125 | "});",
126 | "",
127 | "// Service array must be correctly defined in DID document",
128 | "pm.test(\"'service' array must define Traceability API service endpoint\", function() {",
129 | " const { service } = pm.response.json().didDocument;",
130 | " const entry = service.find((s) => s.type == \"TraceabilityAPI\");",
131 | " pm.expect(entry).to.be.an('object').that.is.not.empty;",
132 | " pm.expect(entry.serviceEndpoint).to.be.a('string').that.is.not.empty;",
133 | "});",
134 | "",
135 | "// If a verificationMethod property is present, the controller property must",
136 | "// match the didDocument.id property.",
137 | "pm.test(\"verification method controller must match did subject\", function() {",
138 | " const { didDocument } = pm.response.json();",
139 | " const vm = didDocument.verificationMethod || [];",
140 | " vm.forEach((m) => pm.expect(m.controller).to.equal(didDocument.id));",
141 | "});"
142 | ],
143 | "type": "text/javascript"
144 | }
145 | }
146 | ],
147 | "protocolProfileBehavior": {
148 | "disabledSystemHeaders": {}
149 | },
150 | "request": {
151 | "auth": {
152 | "type": "bearer",
153 | "bearer": [
154 | {
155 | "key": "token",
156 | "value": "{{access_token}}",
157 | "type": "string"
158 | }
159 | ]
160 | },
161 | "method": "GET",
162 | "header": [
163 | {
164 | "key": "Accept",
165 | "value": "application/json",
166 | "type": "text"
167 | }
168 | ],
169 | "url": {
170 | "raw": "{{API_BASE_URL}}/identifiers/{{ORGANIZATION_DID_WEB}}",
171 | "host": [
172 | "{{API_BASE_URL}}"
173 | ],
174 | "path": [
175 | "identifiers",
176 | "{{ORGANIZATION_DID_WEB}}"
177 | ]
178 | }
179 | },
180 | "response": []
181 | }
182 | ],
183 | "event": [
184 | {
185 | "listen": "prerequest",
186 | "script": {
187 | "type": "text/javascript",
188 | "exec": [
189 | "pm.request.headers.add({key: 'User-Agent', value: 'W3C Traceability Interop Tests'});"
190 | ]
191 | }
192 | },
193 | {
194 | "listen": "test",
195 | "script": {
196 | "type": "text/javascript",
197 | "exec": [
198 | ""
199 | ]
200 | }
201 | }
202 | ],
203 | "variable": [
204 | {
205 | "key": "access_token",
206 | "value": ""
207 | }
208 | ]
209 | }
--------------------------------------------------------------------------------
/docs/tutorials/did-web-discovery/example.env:
--------------------------------------------------------------------------------
1 | CLIENT_ID=""
2 | CLIENT_SCOPE=""
3 | CLIENT_SECRET=""
4 | TOKEN_AUDIENCE=""
5 | TOKEN_ENDPOINT=""
6 | API_BASE_URL=""
7 | ORGANIZATION_DID_WEB=""
--------------------------------------------------------------------------------
/docs/tutorials/did-web-discovery/resources/get-organization-dids-auth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/did-web-discovery/resources/get-organization-dids-auth.png
--------------------------------------------------------------------------------
/docs/tutorials/did-web-discovery/resources/get-organization-dids-headers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/did-web-discovery/resources/get-organization-dids-headers.png
--------------------------------------------------------------------------------
/docs/tutorials/did-web-discovery/resources/get-organization-dids-response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/did-web-discovery/resources/get-organization-dids-response.png
--------------------------------------------------------------------------------
/docs/tutorials/did-web-discovery/resources/get-organization-dids-tests-fail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/did-web-discovery/resources/get-organization-dids-tests-fail.png
--------------------------------------------------------------------------------
/docs/tutorials/did-web-discovery/resources/persist-access-token.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/did-web-discovery/resources/persist-access-token.png
--------------------------------------------------------------------------------
/docs/tutorials/did-web-discovery/resources/select-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/did-web-discovery/resources/select-environment.png
--------------------------------------------------------------------------------
/docs/tutorials/interoperability_suite.postman_environment.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "31a99bc6-b0ea-481a-9713-a7df499e7573",
3 | "name": "Traceability Interoperability",
4 | "values": [
5 | {
6 | "key": "API_BASE_URL",
7 | "value": "s",
8 | "type": "default",
9 | "enabled": true
10 | },
11 | {
12 | "key": "CLIENT_ID",
13 | "value": "",
14 | "type": "default",
15 | "enabled": true
16 | },
17 | {
18 | "key": "CLIENT_SECRET",
19 | "value": "",
20 | "type": "secret",
21 | "enabled": true
22 | },
23 | {
24 | "key": "ORGANIZATION_DID_WEB",
25 | "value": "",
26 | "type": "default",
27 | "enabled": true
28 | },
29 | {
30 | "key": "TOKEN_AUDIENCE",
31 | "value": "",
32 | "type": "default",
33 | "enabled": true
34 | },
35 | {
36 | "key": "TOKEN_ENDPOINT",
37 | "value": "",
38 | "type": "default",
39 | "enabled": true
40 | },
41 | {
42 | "key": "ISSUER_API_BASE_URL",
43 | "value": "{{API_BASE_URL}}",
44 | "type": "default",
45 | "enabled": true
46 | },
47 | {
48 | "key": "ISSUER_CLIENT_ID",
49 | "value": "{{CLIENT_ID}",
50 | "type": "default",
51 | "enabled": true
52 | },
53 | {
54 | "key": "ISSUER_CLIENT_SECRET",
55 | "value": "{{CLIENT_SECRET}",
56 | "type": "secret",
57 | "enabled": true
58 | },
59 | {
60 | "key": "ISSUER_ORGANIZATION_DID_WEB",
61 | "value": "{{ORGANIZATION_DID_WEB}}",
62 | "type": "default",
63 | "enabled": true
64 | },
65 | {
66 | "key": "ISSUER_TOKEN_AUDIENCE",
67 | "value": "{{TOKEN_AUDIENCE}}",
68 | "type": "default",
69 | "enabled": true
70 | },
71 | {
72 | "key": "ISSUER_TOKEN_ENDPOINT",
73 | "value": "{{TOKEN_ENDPOINT}}",
74 | "type": "default",
75 | "enabled": true
76 | },
77 | {
78 | "key": "VERIFIER_API_BASE_URL",
79 | "value": "{{API_BASE_URL}}",
80 | "type": "default",
81 | "enabled": true
82 | },
83 | {
84 | "key": "VERIFIER_CLIENT_ID",
85 | "value": "{{CLIENT_ID}}",
86 | "type": "default",
87 | "enabled": true
88 | },
89 | {
90 | "key": "VERIFIER_CLIENT_SECRET",
91 | "value": "{{CLIENT_SECRET}",
92 | "type": "secret",
93 | "enabled": true
94 | },
95 | {
96 | "key": "VERIFIER_ORGANIZATION_DID_WEB",
97 | "value": "{{ORGANIZATION_DID_WEB}}\n",
98 | "type": "default",
99 | "enabled": true
100 | },
101 | {
102 | "key": "VERIFIER_TOKEN_AUDIENCE",
103 | "value": "{{TOKEN_AUDIENCE}}",
104 | "type": "default",
105 | "enabled": true
106 | },
107 | {
108 | "key": "VERIFIER_TOKEN_ENDPOINT",
109 | "value": "{{TOKEN_ENDPOINT}}",
110 | "type": "default",
111 | "enabled": true
112 | }
113 | ],
114 | "_postman_variable_scope": "environment",
115 | "_postman_exported_at": "2022-11-09T18:57:34.572Z",
116 | "_postman_exported_using": "Postman/9.31.22"
117 | }
--------------------------------------------------------------------------------
/docs/tutorials/presentations-exchange-oauth/README.md:
--------------------------------------------------------------------------------
1 | # Traceability Interop Postman Collection Setup
2 |
3 | This guide provides instructions on how to set up and run the Traceability Interop Postman Collection, [`presentations-exchange-oauth.json`](https://github.com/w3c-ccg/traceability-interop/blob/main/docs/tutorials/presentations-exchange-oauth/presentations-exchange-oauth.json).
4 |
5 | ## Prerequisites
6 |
7 | - [Postman](https://www.postman.com/) must be installed on your computer.
8 |
9 | ## Setting Up the Collection
10 |
11 | Open Postman and click on the "Import" button in the top left corner of the window.
12 |
13 | 
14 |
15 | In the Import dialog, select the "Link" tab, enter the url `https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/presentations-exchange-oauth/presentations-exchange-oauth.json`, and click `Continue`.
16 |
17 | 
18 |
19 | You will be asked to confirm the import.
20 |
21 | 
22 |
23 | After the collection has been imported, you should see a new collection in your Postman Workspace named "Traceability Interop".
24 |
25 | 
26 |
27 | ## Setting Up the Environment
28 |
29 | 1. Click on the "Settings" icon in the top right corner of the Postman window and select "Manage Environments".
30 | 2. Click on the "Add" button to create a new environment.
31 | 3. Give the environment a name, such as "Traceability Interop Environment".
32 | 4. Add the following variables to the environment, replacing the placeholders with your own values:
33 | - `API_BASE_URL`: The base URL for the Traceability Interop API.
34 | - `CLIENT_ID`: The client ID obtained from your OAuth service provider.
35 | - `CLIENT_SCOPE`: The names of the scopes to request from your OAuth service provider. If your OAuth service provider requires that you name the specific scopes that should be included in the auth token, you should provide a value for this variable.
36 | - `CLIENT_SECRET`: The client secret obtained from your OAuth service provider. 🔥 Be especially careful with `CLIENT_SECRET`🔥, If it is stolen it will allow an attacker the ability to perform all api operations supported by your service provider.
37 | - `TOKEN_AUDIENCE`: This value is used to identify the service provider API that the token will be used to access. You may need to configure your identity provider and token endpoint to support this value.
38 | - `TOKEN_ENDPOINT`: This is the endpoint used to obtain an access token for Machine to Machine connection secured via CLIENT_ID
and CLIENT_SECRET
.
39 | 5. Save the environment by clicking on the "Add" button.
40 |
41 | ## Running the Collection
42 |
43 | 1. Select the "Traceability Interop" collection in the Postman Workspace.
44 | 2. In the top right corner of the Postman window, select the environment you just created from the dropdown list.
45 | 3. Click on the "Runner" button in the top right corner of the window to open the Collection Runner.
46 | 4. In the Collection Runner, select the "Traceability Interop" collection and the environment you created earlier.
47 | 5. Click on the "Start Test" button to run the collection.
48 | 6. Observe the results of the API requests in the Collection Runner. The responses from the API will be displayed in the "Tests" tab for each request.
49 | 7. If a request fails, you can examine the response to see what went wrong.
50 |
51 | By following these steps, you should now be able to successfully run the Traceability Interop Postman Collection and test the Traceability Interop API.
52 |
--------------------------------------------------------------------------------
/docs/tutorials/presentations-exchange-oauth/resources/confirm-import.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/presentations-exchange-oauth/resources/confirm-import.png
--------------------------------------------------------------------------------
/docs/tutorials/presentations-exchange-oauth/resources/import-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/presentations-exchange-oauth/resources/import-button.png
--------------------------------------------------------------------------------
/docs/tutorials/presentations-exchange-oauth/resources/import-complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/presentations-exchange-oauth/resources/import-complete.png
--------------------------------------------------------------------------------
/docs/tutorials/presentations-exchange-oauth/resources/import-from-link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/presentations-exchange-oauth/resources/import-from-link.png
--------------------------------------------------------------------------------
/docs/tutorials/report-generation/README.md:
--------------------------------------------------------------------------------
1 | Be careful generating reports from postman.
2 |
3 | Ensure that no senstive data is included in the report.
4 |
5 | ```
6 | npm install -g newman newman-reporter-html
7 | ```
8 |
9 | ```sh
10 | newman run ./report-tester.collection.json \
11 | --reporters cli,html,json
12 | ```
13 |
--------------------------------------------------------------------------------
/docs/tutorials/report-generation/build-index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const path = require('path');
3 | const fs = require('fs');
4 | const yargs = require('yargs/yargs');
5 | const reportCleaner = require('./newman-json-sanitizer');
6 |
7 | const readFilesSync = (dir) => {
8 | const files = [];
9 | fs.readdirSync(dir).forEach((filename) => {
10 | const { name, ext } = path.parse(filename);
11 |
12 | const filepath = path.resolve(dir, filename);
13 | const stat = fs.statSync(filepath);
14 | const isFile = stat.isFile();
15 | if (isFile) {
16 | files.push({
17 | filepath,
18 | name,
19 | ext,
20 | stat,
21 | content: fs.readFileSync(filepath).toString(),
22 | });
23 | }
24 | });
25 |
26 | const sortArgs = {
27 | numeric: true,
28 | sensitivity: 'base',
29 | };
30 |
31 | files.sort((a, b) => a.name.localeCompare(b.name, undefined, sortArgs));
32 | return files;
33 | };
34 |
35 | const cleanAndMoveReports = (relativePath) => {
36 | readFilesSync(path.join(process.cwd(), relativePath)).map((f) => {
37 | const cleanerName = (f.name + f.ext).replace('newman-run-report-', '');
38 | let { content } = f;
39 | if (f.ext === '.json') {
40 | content = JSON.stringify(reportCleaner(JSON.parse(content)), null, 2);
41 | }
42 | fs.writeFileSync(path.join(__dirname, `../../reports/${cleanerName}`), content);
43 | return cleanerName;
44 | });
45 | };
46 |
47 | const buildReportsIndex = (folder) => {
48 | const reports = readFilesSync(path.join(__dirname, '../../reports'))
49 | .filter((f) => f.name !== 'index' && ['.json', '.html'].includes(f.ext))
50 | .map((f) => `https://w3id.org/traceability/interoperability/reports/${folder}/${f.name + f.ext}`);
51 | fs.writeFileSync(path.join(__dirname, '../../reports/index.json'), JSON.stringify({ items: reports }, null, 2));
52 | };
53 |
54 | (() => {
55 | const { argv } = yargs(process.argv.slice(2))
56 | .option('index', {
57 | default: true,
58 | describe: 'Generate index.json, negate with --no-index.',
59 | type: 'boolean',
60 | })
61 | .option('sanitize', {
62 | default: true,
63 | describe: 'Sanitize and collect test output, negate with --no-sanitize.',
64 | type: 'boolean',
65 | })
66 | .option('folder', {
67 | describe: 'Subfolder to use when generating index.json links. Required unless --no-index is specified.',
68 | type: 'string',
69 | choices: ['interoperability', 'conformance'],
70 | alias: 'f',
71 | })
72 | .check((args, _) => {
73 | if (args.index && !args.folder) {
74 | throw new Error('Missing required argument: folder');
75 | }
76 | return true;
77 | });
78 |
79 | if (argv.sanitize) {
80 | try {
81 | cleanAndMoveReports('./newman');
82 | } catch (e) {
83 | console.log(e);
84 | console.log('No newman reports to clean');
85 | }
86 | }
87 |
88 | if (argv.index) {
89 | buildReportsIndex(argv.folder);
90 | }
91 |
92 | // consider removing reports older than 1 month / 1 year...
93 | })();
94 |
--------------------------------------------------------------------------------
/docs/tutorials/report-generation/newman-json-sanitizer.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | jsonReport.run.executions will contain:
4 |
5 | - 🔥 OAuth ACCESS_TOKENs 🔥
6 | - 🔥 OAuth CLIENT_ID 🔥
7 | - 🔥 OAuth CLIENT_SECRET 🔥
8 |
9 | */
10 |
11 | // 🔥 this is the most dangerous function
12 | const cleanExecutions = (executions) => {
13 | const safeExecutions = [];
14 | executions.forEach((execution) => {
15 | safeExecutions.push({
16 | id: execution.id,
17 | cursor: execution.cursor,
18 | item: {
19 | id: execution.item.id,
20 | name: execution.item.name,
21 | },
22 | // 🔥 we opt to not include any details of the request, and only status and timing from the response
23 | // request details can be inferred from collection data.
24 | // NOTE: The `response` may be missing if there was a request error, e.g.,
25 | // ENOTFOUND in the case of missing base url parameters.
26 | response: {
27 | id: execution.response?.id,
28 | status: execution.response?.status,
29 | code: execution.response?.code,
30 | responseTime: execution.response?.responseTime,
31 | responseSize: execution.response?.responseSize,
32 | },
33 | assertions: execution.assertions,
34 | });
35 | });
36 | return safeExecutions;
37 | };
38 |
39 | module.exports = (jsonReport) => {
40 | const safeToPublishReport = {
41 | collection: {
42 | info: jsonReport.collection.info,
43 | item: jsonReport.collection.item,
44 | },
45 | run: {
46 | stats: jsonReport.run.stats,
47 | timings: jsonReport.run.timings,
48 | executions: cleanExecutions(jsonReport.run.executions),
49 | },
50 | };
51 | return safeToPublishReport;
52 | };
53 |
--------------------------------------------------------------------------------
/docs/tutorials/report-generation/report-tester.collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "_postman_id": "3dd7cd87-3fa5-4f21-b598-350eebd0d67d",
4 | "name": "Test Report Demo",
5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6 | },
7 | "item": [
8 | {
9 | "name": "Discover API Configuration",
10 | "event": [
11 | {
12 | "listen": "test",
13 | "script": {
14 | "exec": [
15 | "const jsonResponse = pm.response.json();",
16 | "",
17 | "pm.test(\"The DID Document MUST contain 'assertionMethod' DID URL\", function () {",
18 | " pm.expect(jsonResponse.didDocument.assertionMethod).to.be.an(\"array\");",
19 | " pm.expect(jsonResponse.didDocument.assertionMethod[0]).to.be.a(\"string\");",
20 | " pm.environment.set(\"issuer_did_url\", jsonResponse.didDocument.assertionMethod[0]);",
21 | "});",
22 | "",
23 | "pm.test(\"The DID Document MUST contain 'authentication' DID URL\", function () {",
24 | " pm.expect(jsonResponse.didDocument.authentication).to.be.an(\"array\");",
25 | " pm.expect(jsonResponse.didDocument.authentication[0]).to.be.a(\"string\");",
26 | " pm.environment.set(\"holder_did_url\", jsonResponse.didDocument.authentication[0]);",
27 | "});",
28 | "",
29 | "pm.test(\"The DID Document MUST contain 'service'\", function () {",
30 | " pm.expect(jsonResponse.didDocument.service).to.be.an(\"array\");",
31 | " pm.environment.set(\"traceability_api_root\", jsonResponse.didDocument.service[0].serviceEndpoint);",
32 | "});"
33 | ],
34 | "type": "text/javascript"
35 | }
36 | }
37 | ],
38 | "request": {
39 | "method": "GET",
40 | "header": [
41 | {
42 | "key": "Accept",
43 | "value": "application/json",
44 | "type": "text"
45 | }
46 | ],
47 | "url": {
48 | "raw": "https://api.did.actor/identifiers/did:web:api.did.actor:api",
49 | "protocol": "https",
50 | "host": [
51 | "api",
52 | "did",
53 | "actor"
54 | ],
55 | "path": [
56 | "identifiers",
57 | "did:web:api.did.actor:api"
58 | ]
59 | }
60 | },
61 | "response": []
62 | },
63 | {
64 | "name": "Issue Credential",
65 | "event": [
66 | {
67 | "listen": "prerequest",
68 | "script": {
69 | "exec": [
70 | ""
71 | ],
72 | "type": "text/javascript"
73 | }
74 | },
75 | {
76 | "listen": "test",
77 | "script": {
78 | "exec": [
79 | "const {verifiableCredential} = pm.response.json();",
80 | "",
81 | "pm.test(\"The Verifiable Credential MUST have a 'proof'\", function () {",
82 | " pm.expect(verifiableCredential.proof).to.be.an(\"object\");",
83 | " pm.environment.set(\"verifiable_credential\", JSON.stringify(verifiableCredential));",
84 | "});",
85 | ""
86 | ],
87 | "type": "text/javascript"
88 | }
89 | }
90 | ],
91 | "request": {
92 | "method": "POST",
93 | "header": [],
94 | "body": {
95 | "mode": "raw",
96 | "raw": "{\n \"credential\": {\n \"@context\": [\n \"https://www.w3.org/2018/credentials/v1\"\n ],\n \"id\": \"urn:uuid:07aa969e-b40d-4c1b-ab46-ded252003ded\",\n \"type\": [\n \"VerifiableCredential\"\n ],\n \"issuer\": \"did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn\",\n \"issuanceDate\": \"{{$isoTimestamp}}\",\n \"credentialSubject\": {\n \"id\": \"did:key:z6MktiSzqF9kqwdU8VkdBKx56EYzXfpgnNPUAGznpicNiWfn\"\n }\n },\n \"options\": {\n \"type\": \"Ed25519Signature2018\"\n }\n}",
97 | "options": {
98 | "raw": {
99 | "language": "json"
100 | }
101 | }
102 | },
103 | "url": {
104 | "raw": "{{traceability_api_root}}/credentials/issue",
105 | "host": [
106 | "{{traceability_api_root}}"
107 | ],
108 | "path": [
109 | "credentials",
110 | "issue"
111 | ]
112 | }
113 | },
114 | "response": []
115 | },
116 | {
117 | "name": "Verify Credential",
118 | "event": [
119 | {
120 | "listen": "test",
121 | "script": {
122 | "exec": [
123 | "const verification = pm.response.json()",
124 | "",
125 | "pm.test(\"The Verifiable Credential MUST have been verified\", function () {",
126 | " pm.expect(verification.verified).to.eql(true);",
127 | "});",
128 | ""
129 | ],
130 | "type": "text/javascript"
131 | }
132 | }
133 | ],
134 | "request": {
135 | "method": "POST",
136 | "header": [],
137 | "body": {
138 | "mode": "raw",
139 | "raw": "{\n \"verifiableCredential\": {{verifiable_credential}}\n}",
140 | "options": {
141 | "raw": {
142 | "language": "json"
143 | }
144 | }
145 | },
146 | "url": {
147 | "raw": "{{traceability_api_root}}/credentials/verify",
148 | "host": [
149 | "{{traceability_api_root}}"
150 | ],
151 | "path": [
152 | "credentials",
153 | "verify"
154 | ]
155 | }
156 | },
157 | "response": []
158 | }
159 | ],
160 | "event": [
161 | {
162 | "listen": "prerequest",
163 | "script": {
164 | "type": "text/javascript",
165 | "exec": [
166 | "pm.request.headers.add({key: 'User-Agent', value: 'W3C Traceability Interop Tests'});"
167 | ]
168 | }
169 | },
170 | {
171 | "listen": "test",
172 | "script": {
173 | "type": "text/javascript",
174 | "exec": [
175 | ""
176 | ]
177 | }
178 | }
179 | ]
180 | }
--------------------------------------------------------------------------------
/docs/tutorials/resources/configure-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/configure-environment.png
--------------------------------------------------------------------------------
/docs/tutorials/resources/create-workspace-details.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/create-workspace-details.png
--------------------------------------------------------------------------------
/docs/tutorials/resources/create-workspace-start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/create-workspace-start.png
--------------------------------------------------------------------------------
/docs/tutorials/resources/import-collection-confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/import-collection-confirm.png
--------------------------------------------------------------------------------
/docs/tutorials/resources/import-collection-link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/import-collection-link.png
--------------------------------------------------------------------------------
/docs/tutorials/resources/import-environment-confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/import-environment-confirm.png
--------------------------------------------------------------------------------
/docs/tutorials/resources/import-environment-link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/import-environment-link.png
--------------------------------------------------------------------------------
/docs/tutorials/resources/import-start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/import-start.png
--------------------------------------------------------------------------------
/docs/tutorials/resources/select-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/tutorials/resources/select-environment.png
--------------------------------------------------------------------------------
/docs/tutorials/traceable-presentation-workflow/README.md:
--------------------------------------------------------------------------------
1 | # Traceability Interop Postman Collection Setup
2 |
3 | This guide provides instructions on how to set up and run the Traceability Interop Postman Collection, [`traceable-presentation-workflow.postman_collection.json`](https://github.com/w3c-ccg/traceability-interop/blob/main/docs/tutorials/traceable-presentation-workflow/traceable-presentation-workflow.postman_collection.json).
4 |
5 | ## Prerequisites
6 |
7 | - [Postman](https://www.postman.com/) must be installed on your computer.
8 |
9 | ## Setting Up the Collection
10 |
11 | Open Postman and click on the "Import" button in the top left corner of the window.
12 |
13 | In the Import dialog, select the "Link" tab, enter the url `https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/docs/tutorials/traceable-presentation-workflow/traceable-presentation-workflow.postman_collection.json`, and click `Continue`.
14 |
15 | You will be asked to confirm the import.
16 |
17 | After the collection has been imported, you should see a new collection in your Postman Workspace named "Workflow Tutorial".
18 |
19 | ## Setting Up the Environment
20 |
21 | 1. Click on the "Settings" icon in the top right corner of the Postman window and select "Manage Environments".
22 | 2. Click on the "Add" button to create a new environment.
23 | 3. Give the environment a name, such as "Traceability Interop Environment".
24 | 4. Add the following variables to the environment, replacing the placeholders with your own values. These should reflect the Machine to Machine OAuth Application configured on the Verifier's platform, used for the Holder to make the Traceable Presentation which includes Workflow details:
25 | - `API_BASE_URL`: Verifier platform's base URL.
26 | - `CLIENT_ID`: The client ID for the M2M application, to be used by the Holder.
27 | - `CLIENT_SCOPE`: The names of the scopes to request from your OAuth service provider. If your OAuth service provider requires that you name the specific scopes that should be included in the auth token, you should provide a value for this variable.
28 | - `CLIENT_SECRET`: The client secret provided from the Verifier to the Holder. 🔥 Be especially careful with `CLIENT_SECRET`🔥.
29 | - `TOKEN_ENDPOINT`: This is the endpoint used to obtain an access token for M2M connection secured via CLIENT_ID
and CLIENT_SECRET
.
30 | - `ORGANIZATION_DID_WEB`: Verifier's `did:web` used for service endpoint discovery, on which the presentation is made.
31 | 5. Save the environment by clicking on the "Add" button.
32 |
33 | ## Running the Collection
34 |
35 | 1. Select the "Workflow Tutorial" collection in the Postman Workspace.
36 | 2. In the top right corner of the Postman window, select the environment you just created from the dropdown list.
37 | 3. Click on the "Runner" button in the top right corner of the window to open the Collection Runner.
38 | 4. In the Collection Runner, select the "Workflow Tutorial" collection and the environment you created earlier.
39 | 5. Click on the "Start Test" button to run the collection.
40 | 6. Observe the results of the API requests in the Collection Runner. The responses from the API will be displayed in the "Tests" tab for each request.
41 | 7. If a request fails, you can examine the response to see what went wrong.
42 |
43 | By following these steps, you should now be able to successfully run the Traceability Interop Postman Collection and test the Traceability Interop API.
44 |
--------------------------------------------------------------------------------
/docs/weekly-minutes/README.md:
--------------------------------------------------------------------------------
1 | # W3C CCG Weekly Minutes
2 |
3 |
4 |
5 | Published meeting minutes consist of three files which need to be prepared and added to the [`w3c-ccg/meetings` GitHub repository](https://github.com/w3c-ccg/meetings). This document outlines the procedures required to prepare these files and add them to the repository.
6 |
7 | - `irc.log`
8 | - `audio.ogg`
9 | - `group.txt`
10 |
11 | ## Download IRC Logs
12 |
13 | To download the IRC logs, visit the [Scribe tool](https://w3c-ccg.github.io/meetings/scribe-tool/). Select "Traceability" from the "Weekly Meeting" dropdown, enter the appropriate date in the date picker, and click "Retrieve Raw Logs". All of these UI elements are located at the bottom-right corner of the window.
14 |
15 |
16 |
17 | Select the "Raw IRC Log" tab at the bottom-left of the display, and copy/paste the contents of the text area into a file called `irc.log`. Clean this file up as needed, e.g., to remove `s/foo/bar/` comments and any other relevant items.
18 |
19 |
20 |
21 | ## Download Audio
22 |
23 | With the "Weekly Meeting" and date picker elements still properly filled out, click on the "Download Audio" button.
24 |
25 |
26 |
27 | You will be redirected to a new page, which will begin playing the audio from the selected meeting. Listen for a moment to ensure that the meeting was properly recorded, then click on the vertical ellipses and select "Download" to save the `.ogg` file.
28 |
29 | The downloaded file will have a name like `w3c-ccg-traceability-2022-08-09.ogg`; rename this file to `audio.ogg`.
30 |
31 |
32 |
33 |
34 | ## Commit `group.txt` file to GitHub
35 |
36 | _Note that you must have appropriate permissions to add files to the `w3c-ccg/meetings` GitHub repository. If you do not have this permission level, you will be unable to add files directly._
37 |
38 | Visit the [W3C Credentials Community Group meeting transcripts](https://github.com/w3c-ccg/meetings) GitHub repository and select "Add file" -> "Create new file".
39 |
40 |
41 |
42 | In the `Name your file...` text box, add both a directory name and file name for the `group.txt` file. The directory name should include the appropriate date and meeting group suffix, e.g., `2022-08-09-traceability`. The contents of the file should simply be the word `Traceability`.
43 |
44 |
45 |
46 | Be sure to commit the new `group.txt` file by clicking the "Commit new file" button at the bottom of the page.
47 |
48 |
49 |
50 | ## Upload `irc.log` and `audio.ogg` to GitHub
51 |
52 | From within the newly created folder (`2022-08-09-traceability` in this example), select "Add file" -> "Upload Files"
53 |
54 |
55 |
56 | Drag or select the `irc.log` and `audio.ogg` files that you saved earlier and commit your changes.
57 |
58 |
59 |
60 | You should now have three files committed to the new folder, which will kick off a workflow job to handle the rest of the publishing steps.
61 |
62 |
63 |
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/add-group-file-name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/add-group-file-name.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/add-group-file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/add-group-file.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/click-download-audio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/click-download-audio.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/commit-group-file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/commit-group-file.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/download-audio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/download-audio.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/files-uploaded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/files-uploaded.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/play-audio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/play-audio.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/raw-irc-logs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/raw-irc-logs.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/select-meeting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/select-meeting.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/upload-files-confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/upload-files-confirm.png
--------------------------------------------------------------------------------
/docs/weekly-minutes/resources/upload-files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/docs/weekly-minutes/resources/upload-files.png
--------------------------------------------------------------------------------
/environment-setup/create-pat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/environment-setup/create-pat.png
--------------------------------------------------------------------------------
/environment-setup/onboard-register.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # This script is a wrapper to call the onboard-register workflow in the
4 | # w3c-ccg/traceability-interop repository. Options correspond to inputs for the
5 | # workflow
6 | #
7 | # Examples:
8 | #
9 | # # Register contents of secrets.b64 under prefix VENDOR_PREFIX_. This will
10 | # # fail if the secrets being registered already exist.
11 | #
12 | # onboard-register.sh -p VENDOR_PREFIX_ secrets.b64
13 | #
14 | # # Register contents of secrets.b64 under prefix VENDOR_PREFIX_ and
15 | # # overwrite any existing values for those secrets.
16 | #
17 | # onboard-register.sh -p VENDOR_PREFIX_ -o secrets.b64
18 |
19 | set -o errexit
20 | set -o nounset
21 | set -o pipefail
22 |
23 | usage() { echo "Usage: $0 -p [-o] dotenv" 1>&2; exit 1; }
24 |
25 | OVERWRITE="false"
26 | while getopts "p:o" o; do
27 | case "${o}" in
28 | p)
29 | PREFIX=${OPTARG}
30 | ;;
31 | o)
32 | OVERWRITE="true"
33 | ;;
34 | *)
35 | usage
36 | ;;
37 | esac
38 | done
39 | shift $((OPTIND-1))
40 |
41 | if [ -z "$1" ] || [ ! -f "$1" ]; then
42 | echo "You must specify a valid dotenv file"
43 | exit 1
44 | fi;
45 |
46 | GITHUB_REPOSITORY='w3c-ccg/traceability-interop'
47 | GITHUB_TOKEN=$(gh auth status -t 2>&1 | grep Token | awk '{print $3}')
48 | DOTENV=`cat $1`
49 |
50 | if [ -z "$GITHUB_TOKEN" ]; then
51 | echo "You must first authenticate with 'gh auth login'"
52 | exit 1
53 | fi
54 |
55 | gh workflow run onboard-register.yml --repo "$GITHUB_REPOSITORY" \
56 | -f token="$GITHUB_TOKEN" \
57 | -f prefix="$PREFIX" \
58 | -f dotenv="$DOTENV" \
59 | -f overwrite="$OVERWRITE"
60 |
--------------------------------------------------------------------------------
/environment-setup/onboard-rotate.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # This script is a wrapper to call the onboard-rotate workflow in the
4 | # w3c-ccg/traceability-interop repository.
5 |
6 | set -o errexit
7 | set -o nounset
8 | set -o pipefail
9 |
10 | GITHUB_REPOSITORY='w3c-ccg/traceability-interop'
11 | GITHUB_TOKEN=$(gh auth status -t 2>&1 | grep Token | awk '{print $3}')
12 |
13 | if [ -z "$GITHUB_TOKEN" ]; then
14 | echo "You must first authenticate with 'gh auth login'"
15 | exit 1
16 | fi
17 |
18 | gh workflow run onboard-rotate.yml --repo "$GITHUB_REPOSITORY" \
19 | -f token="$GITHUB_TOKEN"
20 |
--------------------------------------------------------------------------------
/environment-setup/pubkey.asc:
--------------------------------------------------------------------------------
1 | -----BEGIN PGP PUBLIC KEY BLOCK-----
2 |
3 | mQINBGLN138BEADepbUj/nnG6LwSjLS4seHL8eDlsBIdajBa67c7Qfn8J8iuyTdb
4 | ona5DY3q9yYy9FxSM29XzsB7I9PDWwovVF+DJrfOwH/LxuRh2XG2ijXGGVv9gbnT
5 | ERu4l3kWSN5RmmJy+cApvF5LmHtQmDvkiJeU/e/UzdFWcm341RTCnJUm+3Ze2iS3
6 | p9tZeej5T3yFxEw3zls82dG6FcBnylFCiV5SY5ExK8AFB4SfOh4d3O0sV0tdrhT1
7 | Llf9BN+tjtmEf66Zh+EHUcqiFKqUyqsYnJErdpriRbOC/VcY6dNYvpPzbmVey6vL
8 | /PO4UY1eDrAehg4iLcCIjFYwgL1/zwZSR8lugB4Roojys8feYrRiRhTQ7/PpCCj0
9 | ipCgLY+Vv8L/BJdKDyyr9eva/w+ACV8Xa2kzgNMMUtB3QChXk3T5C1fiXZsgMWCR
10 | NNmnR02fqbpV/m5OWBnxAjToVa/WeD39+i1n4qOXGAIDao81wb9xktl2JPKNWSan
11 | HY7sPB4UNVG5sob4xu8B8qFnYYcHK138g+Rg0lAFqHZQ0mqsCIync3uOssKqzb55
12 | mwNDUYjZ3Z0ci4lQX9Qxvkz1ZHK/Nv0f3CdII39Zv/e6AIQc5O167q7RERqWGRdE
13 | JjTqENGZwbXEkOrUA8MZzwjD8nGAeqWtJps6k9Uj79zUFv9DuGdbu5Z9VQARAQAB
14 | tDZ3M2MtY2NnL3RyYWNlYWJpbGl0eS1pbnRlcm9wICh0ZXN0IHN1aXRlIHJlZ2lz
15 | dHJhdGlvbimJAk4EEwEKADgWIQShgULvShICcSJIMIIBoYiM7XujPwUCYs3XfwIb
16 | DQULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRABoYiM7XujP5ZXEACoxSHaH7s5
17 | kooVb3VjT3WoB4Vuzb3zEyp/iFwLHe3FaIQnYdNQxbec8WZVKWD4nxMhtGAr51hs
18 | sC8JRnIzDDiCl55dH/ivVgpUM2hLwNRxjyMGAJgzOfVYhaqPAexjFB5m0o5ZL+iP
19 | d1mkwlivaO2VtMNM0moN1uedq/C4CLL0y3BUFtKPuYALDdZ75rfmp6Jfi/eI+hLf
20 | xTJRzpvk9MBonqwz7Lo8ZSRcFm+KUE3Kvx6HlBcrhqL/SR0iq1OCpO6sVa6Yt3rD
21 | YGd7edu0cv1LAbcIfJZ/aj46ju3KZCn+80xizCRw2S+hrwVNMjRgx9SWsT3MKgOC
22 | AY23nSMO6vXPfrcgh0r4iQP2oikOGLrExLdyWsNzqqI7/nj4XhqiXaeIPt0aJSWl
23 | imCF1e6kJFaOi7NcfUsUujnd+YCkI/GetYTNEjTwDN10yWDPnnzdKeNr0yM0JogR
24 | Xb+TDuumdXbbozd6XtevYXJsfzCflFfu7Q0lTsGFTbGp0jaHyrMtTugUG6+R3caP
25 | bowZp20Jd7z6FpzM7fAyXAoJfIjWUWyM4qXmfN+nAmkMTsgQW1QsUbeaQZIkZCn4
26 | 6m2WOr6rj/1qzpyNdAO8DwAYPqaDmNTGYS6sEYY98oDA1r2HlbpDp83AtyWVa+20
27 | VcgrfAqFk9w4tPArCkHmllRI2DJl3sUARQ==
28 | =TWPN
29 | -----END PGP PUBLIC KEY BLOCK-----
30 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "packages/*"
4 | ],
5 | "version": "0.0.0"
6 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "traceability-interop",
3 | "version": "0.0.1",
4 | "description": "An enterprise grade HTTP API for leveraging [W3C Decentralized Identifiers](https://www.w3.org/TR/did-core/) and [W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model/) with [W3C CCG Traceability Vocabulary](https://w3c-ccg.github.io/traceability-vocab/) and the [VC API](https://w3c-ccg.github.io/vc-api/) when possible.",
5 | "main": "index.js",
6 | "directories": {
7 | "doc": "docs",
8 | "test": "tests"
9 | },
10 | "scripts": {
11 | "shove": "git add -A; git commit -m 'chore: :rocket: testing ci'; git push origin main",
12 | "clean": "npm run report:clean",
13 | "report:generate": "newman run",
14 | "postreport:generate": "npm run report:prepare",
15 | "report:sanitize": "node ./docs/tutorials/report-generation/build-index.js --no-index",
16 | "report:index": "node ./docs/tutorials/report-generation/build-index.js --no-sanitize",
17 | "report:clean": "rm -rf ./docs/reports/*",
18 | "postinstall": "lerna bootstrap",
19 | "clean:lock": "npx lerna exec 'rm -rf package-lock.json node_modules'",
20 | "install:clean": "npx lerna clean -y && rm -rf node_modules && npm i",
21 | "install:ci": "npm ci --ignore-scripts && lerna link && lerna bootstrap",
22 | "lint": "lerna run lint --stream",
23 | "lint:docs": "eslint --ext .html docs --fix",
24 | "format": "lerna run format --stream",
25 | "format:docs": "prettier --write docs/**/*.html",
26 | "validate-spec": "npx swagger-cli validate docs/openapi/openapi.yml",
27 | "preserve": "npx swagger-cli bundle docs/openapi/openapi.yml -o docs/openapi/openapi.json --dereference",
28 | "serve": "npx serve ./docs",
29 | "testdata": "node ./tests/generate-testdata.js"
30 | },
31 | "repository": {
32 | "type": "git",
33 | "url": "git+https://github.com/w3c-ccg/traceability-interop.git"
34 | },
35 | "author": "",
36 | "license": "ISC",
37 | "bugs": {
38 | "url": "https://github.com/w3c-ccg/traceability-interop/issues"
39 | },
40 | "homepage": "https://github.com/w3c-ccg/traceability-interop#readme",
41 | "devDependencies": {
42 | "@digitalbazaar/did-method-key": "^5.1.0",
43 | "@digitalbazaar/ed25519-signature-2018": "^4.0.0",
44 | "@digitalbazaar/ed25519-verification-key-2018": "^4.0.0",
45 | "@digitalbazaar/vc": "^6.0.1",
46 | "@html-eslint/eslint-plugin": "^0.19.0",
47 | "@html-eslint/parser": "^0.19.0",
48 | "credentials-context": "^2.0.0",
49 | "eslint": "^8.40.0",
50 | "eslint-config-airbnb-base": "^15.0.0",
51 | "eslint-plugin-import": "^2.27.5",
52 | "eslint-plugin-jest": "^27.2.1",
53 | "eslint-plugin-prettier": "^4.2.1",
54 | "jsonld": "^8.1.1",
55 | "jsonld-signatures": "^11.1.0",
56 | "klona": "^2.0.6",
57 | "prettier": "^2.8.8"
58 | },
59 | "dependencies": {
60 | "@apidevtools/swagger-cli": "^4.0.4",
61 | "lerna": "^6.6.2",
62 | "newman": "^5.3.2",
63 | "newman-reporter-htmlextra": "^1.22.11",
64 | "yargs": "^17.7.2"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/reporting/README.md:
--------------------------------------------------------------------------------
1 | # Test Result Reporting
2 |
3 | ## Environment Setup
4 |
5 | To build and run the test reporting, first install and run either [miniconda](https://docs.conda.io/en/latest/miniconda.html) or full [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html)
6 |
7 |
8 | Once that is installed, you can create the reporting environment with the following command:
9 |
10 | ```bash
11 | $ conda env create -f environment.yml python=3.9
12 | ```
13 |
14 |
15 | And then activate it:
16 |
17 | ```bash
18 | $ conda activate reporting
19 | ```
20 |
21 | ## Run reporting
22 |
23 | The reporter can be run from your local machine with one of the following command:
24 |
25 | ```bash
26 | $ ./reporter.py --conformance
27 | $ ./reporter.py --interoperability
28 | ```
29 |
30 | It will automatically fetch the latest test results, process them, and launch a server hosting the dashboard at [http://localhost:8050/](http://localhost:8050/)
31 |
32 | Test results are sourced from the JSON test results published in github pages in one of the following locations based on the provided command-line options (either `--conformance` or `--interoperability`)
33 |
34 | - [Interoperability test results](https://w3c-ccg.github.io/traceability-interop/reports/interoperability/index.json)
35 | - [Conformance test results](https://w3c-ccg.github.io/traceability-interop/reports/conformance/index.json)
36 |
37 | The reporter can also be run in CI mode, which will find test output in the `docs/reports` folder on the test runner instead of downloading published report output. If you want to test this mode locally, i.e., during development, you will need to run the postman test suite and post-process the results into the `docs/reports` folder yourself before running `reporter.py`.
38 |
39 | ```bash
40 | $ ./reporter.py --mode ci --conformance
41 | $ ./reporter.py --mode ci --interoperability
42 | ```
43 |
44 | To get a full list of reporter options, you can execute the reporter with the help parameter:
45 | ```bash
46 | $ ./reporter.py -h
47 | usage: reporter.py [-h] [--mode [{all,data,html,dashboard,ci}]] (-c | -i)
48 |
49 | Interop test results reporting utility
50 |
51 | optional arguments:
52 | -h, --help show this help message and exit
53 | --mode [{all,data,html,dashboard,ci}]
54 | mode to run the reporter in
55 |
56 | Report Type:
57 | One of the following options MUST be specified.
58 |
59 | -c, --conformance generate a report based on the most recently published conformance testing output.
60 | -i, --interop generate a report based on the most recently publised interoperability testing output.
61 | ```
62 |
63 | ## Module Description
64 |
65 | There are three main modules:
66 |
67 | - `./postman_reporter/report_data.py` — go get the data, link it up, create appropriate data frames, and store them as CSV for easy use
68 | - `./postman_reporter/report_static.py` — generate a static HTML report for use with gh-pages
69 | - `./postman_reporter/report_dashboard.py` — the latter half of this app that spins up a dash app on flask for actually working with the test results
70 | - `reporter.py` — the main binary that runs one or more modules as listed above, based on command line arguments
71 |
72 | ## Output
73 |
74 | After running the reporter you will see a dashboard in your browser
75 | 
76 |
77 | In addition to the summary stats multiple drill through visualizations that cross compare results and identify problems in red are available
78 | 
79 | 
80 |
81 | There is also a searchable and filterable table of all unit test results
82 | 
--------------------------------------------------------------------------------
/reporting/assets/conformance.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | W3C Supply Chain Traceability Conformance Test Results
8 |
10 |
91 |
92 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
Traceability Conformance Test Results
103 |
104 |
105 |
106 |
109 |
110 |
111 |
Summary
112 |
113 | {{ summary_text }}
114 |
115 |
Provider Summary
116 |
117 | {% for card in cards_single %}
118 | {{ card }}
119 | {% endfor %}
120 |
121 |
122 | {% for card in cards_multi %}
123 | {{ card }}
124 | {% endfor %}
125 |
126 |
Provider & Test Summary
127 |
128 | {{summary_table_single}}
129 |
130 |
131 | {{summary_table_multi}}
132 |
133 |
134 |
135 | {{ facet_tests }}
136 |
137 |
138 |
139 |
140 |
142 |
143 |
Results
144 |
145 |
{{ results_chart }}
146 |
{{ results_tree }}
147 |
148 |
149 |
150 |
152 |
153 |
Details
154 |
155 | {{ details }}
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/reporting/assets/interoperability.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | W3C Supply Chain Traceability Interoperability Test Results
8 |
10 |
83 |
84 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
Traceability Interoperability Test Results
95 |
96 |
97 |
98 |
101 |
102 |
103 |
Summary
104 |
105 | {{ summary_text }}
106 |
107 |
Provider Summary
108 |
109 | {% for card in cards_single %}
110 | {{ card }}
111 | {% endfor %}
112 |
113 |
114 | {% for card in cards_multi %}
115 | {{ card }}
116 | {% endfor %}
117 |
118 |
Provider & Test Summary
119 |
120 | {{summary_table_single}}
121 |
122 |
123 | {{summary_table_multi}}
124 |
125 |
126 |
127 | {{ facet_tests }}
128 |
129 |
130 |
131 |
132 |
134 |
135 |
Results
136 |
137 |
{{ results_chart }}
138 |
{{ results_tree }}
139 |
140 |
141 |
142 |
144 |
145 |
Details
146 |
147 | {{ details }}
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/reporting/environment.yml:
--------------------------------------------------------------------------------
1 | name: reporting
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - dash=2.3.1
6 | - dash-bootstrap-components
7 | - Jinja2==3.1.2
8 | - matplotlib=3.5.1
9 | - scipy=1.8.0
10 | - numpy=1.22.3
11 | - pandas=1.4.2
12 | - plotly=5.7.0
13 | - seaborn=0.11.2
14 | - tqdm=4.64.0
15 | - urllib3=1.26.9
16 | - pip=22.0.4
17 | - requests=2.27.1
18 | - pip:
19 | - pyarrow==7.0.0
20 |
--------------------------------------------------------------------------------
/reporting/postman_reporter/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/reporting/postman_reporter/__init__.py
--------------------------------------------------------------------------------
/reporting/postman_reporter/report_config.py:
--------------------------------------------------------------------------------
1 | REPORTS_BASE_URL = "https://w3id.org/traceability/interoperability/reports"
2 | DATA_DIR = "./data/"
3 | CI_DIR = "../docs/reports"
4 | DF_PREFIX = ""
5 | DF_EXT = ".pkl"
6 |
7 | HEADER = [
8 | "Testing Application",
9 | "Project Name",
10 | "Provider",
11 | "Test Type",
12 | "Test Step",
13 | "Assertion",
14 | "Result",
15 | "Error Message",
16 | "Passing",
17 | ]
18 |
19 | COLUMNS_DETAIL = [
20 | "Provider",
21 | "Test Type",
22 | "Test Step",
23 | "Assertion",
24 | "Result",
25 | "Error Message",
26 | "Passing",
27 | ]
28 |
29 | COLUMNS_MAIN = [
30 | "Provider",
31 | "Test Type",
32 | "Test Step",
33 | "Assertion",
34 | "Result",
35 | "Error Message",
36 | ]
37 |
38 | SIDEBAR_STYLE = {
39 | "position": "fixed",
40 | "top": 0,
41 | "left": 0,
42 | "bottom": 0,
43 | "width": "16rem",
44 | "padding": "2rem 1rem",
45 | # "background-color": "#f8f9fa",
46 | }
47 | CONTENT_STYLE = {
48 | "margin-left": "18rem",
49 | "margin-right": "2rem",
50 | "padding": "2rem 1rem",
51 | }
52 |
53 | COLOR_MAP = {
54 | "(?)": "darkgoldenrod",
55 | "Pass": "darkgreen",
56 | "Fail": "darkred",
57 | "Fail (Partial)": "darkgoldenrod",
58 | }
59 |
60 | DEFAULT_REPORT_PATH = ["Test Type", "Provider", "Test Step"]
61 |
--------------------------------------------------------------------------------
/reporting/postman_reporter/report_dashboard.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # %% imports
3 | import warnings
4 | from datetime import datetime
5 |
6 | import dash_bootstrap_components as dbc
7 | import plotly.express as px
8 | import plotly.graph_objects as go
9 | import postman_reporter.report_charts as report_charts
10 | import postman_reporter.reporter_util as reporter_util
11 | from dash import Dash
12 | from dash import dash_table
13 | from dash import dcc
14 | from dash import html
15 | from postman_reporter.report_config import *
16 |
17 | warnings.filterwarnings("ignore")
18 |
19 |
20 | def getApp():
21 | # %% setup
22 | df = reporter_util.get_dataframes()
23 | now = str(datetime.now())
24 |
25 | # %% main components
26 | # sidebar = report_charts.getSidebar()
27 |
28 | # %% charts
29 | summaryText = report_charts.getSummaryText(df["df_summary_provider"], now)
30 | summaryProvider, summaryProviderMulti = report_charts.getCards(
31 | df["df_summary_provider"]
32 | )
33 | facet_tests = report_charts.getFacet(df["df_inter"])
34 | results_chart = report_charts.getSunburst(df["df_details"])
35 | results_tree = report_charts.getTree(
36 | df["df_details"], path=["Provider", "Test Type", "Test Step"]
37 | )
38 |
39 | # %% setup content
40 | overview = [dbc.Col([], xl="12")]
41 | summary = [
42 | dbc.Col(
43 | [
44 | html.H2("Summary"),
45 | html.Div(
46 | summaryText, style={"margin-bottom": "3em", "font-size": "1.2em"}
47 | ),
48 | html.H3("Provider Summary"),
49 | html.Div(summaryProvider, style={"margin-bottom": "2em"}),
50 | html.Div(summaryProviderMulti, style={"margin-bottom": "3em"}),
51 | html.H3("Provider & Test Summary"),
52 | html.Div(
53 | [
54 | report_charts.getTable(
55 | df["df_crosstab_results"], "summary-test-crosstab"
56 | )
57 | ],
58 | style={"width": "60%"},
59 | ),
60 | html.Br(),
61 | html.Div(
62 | [
63 | report_charts.getTable(
64 | df["df_crosstab_results_multi"],
65 | "summary-test-crosstab-multi",
66 | )
67 | ],
68 | style={"width": "80%"},
69 | ),
70 | html.Br(),
71 | html.Br(),
72 | html.Div(
73 | [
74 | dcc.Graph(
75 | id="test-facets",
76 | figure=facet_tests,
77 | config={"displayModeBar": False},
78 | )
79 | ]
80 | ),
81 | # getTable(df_summary_test, 'summary-test'),
82 | html.Br(),
83 | ],
84 | xl="12",
85 | )
86 | ]
87 | results = [
88 | dbc.Col(
89 | [
90 | html.H2("Results"),
91 | dbc.Row(
92 | [
93 | dbc.Col(
94 | [
95 | dcc.Graph(
96 | id="chart-tests",
97 | figure=results_chart,
98 | config={"displayModeBar": False},
99 | ),
100 | ],
101 | xl="6",
102 | ),
103 | dbc.Col(
104 | [
105 | dcc.Graph(
106 | id="chart-tests-tree",
107 | figure=results_tree,
108 | config={"displayModeBar": False},
109 | ),
110 | ],
111 | xl="6",
112 | ),
113 | ]
114 | ),
115 | ],
116 | xl="12",
117 | )
118 | ]
119 | details = [
120 | dbc.Col(
121 | [
122 | html.H2("Details"),
123 | html.Div(
124 | [
125 | report_charts.getTable(
126 | df["df_main"], "results-table", filter=True
127 | )
128 | ],
129 | style={"width": "100%", "max-width": "100%"},
130 | ),
131 | ],
132 | xl="12",
133 | )
134 | ]
135 |
136 | # %% layout
137 | content = html.Div(
138 | id="page-content",
139 | style=CONTENT_STYLE,
140 | children=[
141 | dbc.Row(
142 | [
143 | html.H1("Trace Interop Test Results"),
144 | ]
145 | ),
146 | dbc.Row(
147 | [
148 | dbc.Col(
149 | [
150 | dbc.Row(
151 | id="overview",
152 | children=overview,
153 | style={"margin-bottom": "3em"},
154 | ),
155 | dbc.Row(
156 | id="summary",
157 | children=summary,
158 | style={"margin-bottom": "3em"},
159 | ),
160 | dbc.Row(
161 | id="results",
162 | children=results,
163 | style={"margin-bottom": "3em"},
164 | ),
165 | dbc.Row(
166 | id="details",
167 | children=details,
168 | style={"margin-bottom": "3em"},
169 | ),
170 | ],
171 | xl="12",
172 | )
173 | ]
174 | ),
175 | ],
176 | )
177 |
178 | # %% setup dash
179 | app = Dash(
180 | title="Traceability Interop Test Results",
181 | external_stylesheets=[dbc.themes.DARKLY],
182 | )
183 | app.index_string = reporter_util.get_html_base()
184 | app.layout = html.Div([dcc.Location(id="url"), content])
185 |
186 | return app
187 |
188 |
189 | # %% main it up
190 | if __name__ == "__main__":
191 | app = getApp()
192 | # print(app.layout)
193 | app.run_server()
194 |
--------------------------------------------------------------------------------
/reporting/postman_reporter/report_data.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # %% imports
3 | import json
4 | import warnings
5 | from datetime import datetime
6 |
7 | import pandas as pd
8 |
9 | # disable warnings
10 | warnings.filterwarnings("ignore")
11 | import postman_reporter.reporter_util as reporter_util
12 | from postman_reporter.report_config import *
13 | from tqdm import tqdm
14 |
15 | # %% setup
16 | tqdm.pandas()
17 |
18 |
19 | # %% process initial json
20 | def getData(get_reports, get_json):
21 |
22 | report_sources = get_reports()
23 |
24 | def build_detail(args, execution, assertion):
25 | if "error" not in assertion:
26 | return [
27 | "postman",
28 | args["projectname"],
29 | args["provider"],
30 | args["testtype"],
31 | execution["item"]["name"],
32 | assertion["assertion"],
33 | "Pass",
34 | "",
35 | 1,
36 | ]
37 | else:
38 | return [
39 | "postman",
40 | args["projectname"],
41 | args["provider"],
42 | args["testtype"],
43 | execution["item"]["name"],
44 | assertion["assertion"],
45 | "Fail",
46 | assertion["error"]["message"],
47 | 0,
48 | ]
49 |
50 | reports = []
51 | print("Processing identified reports:", len(report_sources))
52 | report_sources_progress = tqdm(report_sources)
53 | for report_source in report_sources_progress:
54 | rs = report_source.replace(".json", "")
55 | provider = rs.rsplit("-", 1)[1]
56 | if "exchange" in report_source:
57 | provider = " - ".join(rs.split("-")[-2:])
58 | report = get_json(report_source)
59 | name = report["collection"]["info"]["name"]
60 | report_sources_progress.set_description_str(provider + ": " + name)
61 |
62 | for execution in report["run"]["executions"]:
63 | args = {}
64 | args["provider"] = provider
65 | args["projectname"] = "Trace Interop"
66 | args["testtype"] = name
67 | if "assertions" not in execution:
68 | print("No assertions found in execution " + execution["item"]["name"])
69 | continue
70 |
71 | for assertion in execution["assertions"]:
72 | detail = build_detail(args, execution, assertion)
73 | # print(detail)
74 | reports.append(detail)
75 |
76 | # %% persist raw data
77 | print("Persisting raw fetched data")
78 | df_main = pd.DataFrame(reports, columns=HEADER)
79 | # use pipe separation bc of commas and other nastys
80 | df_main.to_csv(
81 | DATA_DIR + "full_report.csv", index=False, quoting=1, quotechar="'", sep="|"
82 | )
83 | with open(DATA_DIR + "full_report.json", "w") as out:
84 | out.write(json.dumps(reports, indent=2))
85 |
86 | # %% clean it up
87 | print("Processing data")
88 | df_main = df_main.loc[df_main["Provider"] != "sanity"]
89 | df_main["Test Type"] = df_main["Test Type"].str.replace(" Tutorial", "")
90 |
91 | df_details = df_main[COLUMNS_DETAIL].copy()
92 | df_main = df_main[COLUMNS_MAIN].copy()
93 |
94 | df_failed = df_details.loc[df_details["Result"] == "Fail"].copy()
95 |
96 | # %% groupings
97 | df_inter = df_details[["Provider", "Test Type", "Test Step", "Passing"]]
98 | df_inter = df_inter.loc[~df_inter["Provider"].str.contains(" - ")].copy()
99 |
100 | df_inter_full = df_details[["Provider", "Test Type", "Test Step", "Passing"]].copy()
101 | df_inter_full["Size"] = 12
102 | df_inter_full["Shape"] = "Box"
103 |
104 | df_summary_test = (
105 | df_details.groupby(["Test Type", "Provider"])["Passing"]
106 | .mean()
107 | .apply(lambda x: "{:.1%}".format(x))
108 | .unstack("Test Type")
109 | .fillna("0%")
110 | .reset_index()
111 | )
112 | df_summary_provider = (
113 | df_details.groupby(["Provider"])["Passing"].mean().fillna(0).reset_index()
114 | )
115 |
116 | df_summary_provider["Passing"] = df_summary_provider["Passing"].apply(
117 | lambda x: "{:.1%}".format(x)
118 | )
119 | df_summary_provider = df_summary_provider.sort_values(["Provider"], ascending=True)
120 |
121 | df_singles = df_details.loc[~df_details["Provider"].str.contains(" - ")].copy()
122 | df_multi = df_details.loc[df_details["Provider"].str.contains(" - ")].copy()
123 |
124 | df_crosstab_results = (
125 | df_singles.groupby(["Test Type", "Provider"])["Passing"]
126 | .mean()
127 | .round(3)
128 | .apply(lambda x: "{:.1%}".format(x))
129 | .unstack()
130 | .fillna("n/a")
131 | .reset_index()
132 | )
133 |
134 | df_crosstab_results_multi = (
135 | df_multi.groupby(["Test Type", "Provider"])["Passing"]
136 | .mean()
137 | .round(3)
138 | .apply(lambda x: "{:.1%}".format(x))
139 | .unstack()
140 | .fillna("n/a")
141 | .reset_index()
142 | )
143 |
144 | # %% save results
145 | print("Saving data frames")
146 | reporter_util.save_dataframes(
147 | [
148 | {"name": "df_main", "data": df_main},
149 | {"name": "df_failed", "data": df_failed},
150 | {"name": "df_details", "data": df_details},
151 | {"name": "df_inter_full", "data": df_inter_full},
152 | {"name": "df_inter", "data": df_inter},
153 | {"name": "df_summary_test", "data": df_summary_test},
154 | {"name": "df_summary_provider", "data": df_summary_provider},
155 | {"name": "df_singles", "data": df_singles},
156 | {"name": "df_multi", "data": df_multi},
157 | {"name": "df_crosstab_results", "data": df_crosstab_results},
158 | {"name": "df_crosstab_results_multi", "data": df_crosstab_results_multi},
159 | ]
160 | )
161 |
162 |
163 | if __name__ == "__main__":
164 | getData()
165 | exit(0)
166 |
--------------------------------------------------------------------------------
/reporting/postman_reporter/report_static.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from datetime import datetime
3 |
4 | import plotly
5 | import postman_reporter.report_charts as report_charts
6 | import postman_reporter.reporter_util as reporter_util
7 | from jinja2 import Template
8 | from postman_reporter.report_config import *
9 |
10 |
11 | def generate_html(template):
12 | df = reporter_util.get_dataframes()
13 | crosstabDF = df["df_crosstab_results"]
14 | crosstabMultiDF = df["df_crosstab_results_multi"]
15 | detailsDF = df["df_details"]
16 | summaryDF = df["df_summary_provider"]
17 |
18 | facet_tests = report_charts.getFacet(df["df_inter"])
19 | results_chart = report_charts.getSunburst(detailsDF)
20 | results_tree = report_charts.getTree(
21 | detailsDF, path=["Provider", "Test Type", "Test Step"]
22 | )
23 |
24 | # Change percentage strings to floats for processing
25 | summaryDF["Passing"] = summaryDF["Passing"].str.rstrip("%").astype("float") / 100.0
26 |
27 | cards = renderSummaryCards(summaryDF)
28 |
29 | args = {"include_plotlyjs": False, "output_type": "div"}
30 | rendered = template.render(
31 | summary_text=renderSummaryText(summaryDF),
32 | cards_single=cards["single"],
33 | cards_multi=cards["multi"],
34 | summary_table_single=renderTable(crosstabDF),
35 | summary_table_multi=renderTable(crosstabMultiDF),
36 | facet_tests=plotly.offline.plot(facet_tests, **args),
37 | results_chart=plotly.offline.plot(results_chart, **args),
38 | results_tree=plotly.offline.plot(results_tree, **args),
39 | details=renderTable(detailsDF),
40 | )
41 |
42 | with open(f"{CI_DIR}/index.html", "wt") as fh:
43 | fh.write(rendered)
44 |
45 |
46 | def renderTable(df):
47 | tpl = Template(
48 | """
49 |
50 |
51 |
52 |
53 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | {% for cell in columns -%}{{cell}} {% endfor -%}
64 |
65 |
66 |
67 | {%for row in rows -%}{% for cell in row -%}{{cell}} {% endfor -%} {% endfor -%}
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | """
76 | )
77 |
78 | return tpl.render(
79 | columns=df.columns,
80 | rows=df.values,
81 | )
82 |
83 |
84 | def renderSummaryText(df):
85 |
86 | tpl = """
87 |
88 | These are the test results for the
89 | Open API for Interoperable Traceability
90 | as of: {now}
91 |
92 |
93 | The highest current % of passed tests by a single provider is: {max:.1%}
94 | The lowest is: {min:.1%}
95 | Across all providers the average % of passed tests is: {avg:.1%}
96 |
97 | """
98 |
99 | return tpl.format(
100 | now=datetime.now(),
101 | min=df["Passing"].min(),
102 | max=df["Passing"].max(),
103 | avg=df["Passing"].mean(),
104 | )
105 |
106 |
107 | def renderSummaryCards(df):
108 |
109 | tpl = """
110 |
111 |
112 |
113 |
114 |
{passed:.1%}
115 |
of tests taken, passed
116 |
117 |
118 |
119 | """
120 |
121 | single = []
122 | for _, r in df[~df["Provider"].str.contains(" - ")].iterrows():
123 | single.append(tpl.format(header=r["Provider"], passed=r["Passing"]))
124 |
125 | multi = []
126 | for _, r in df[df["Provider"].str.contains(" - ")].iterrows():
127 | multi.append(tpl.format(header=r["Provider"], passed=r["Passing"]))
128 |
129 | return {"single": single, "multi": multi}
130 |
--------------------------------------------------------------------------------
/reporting/postman_reporter/reporter_util.py:
--------------------------------------------------------------------------------
1 | # %% imports
2 | import glob
3 | import inspect
4 | import pickle
5 | from typing import List
6 |
7 | from postman_reporter.report_config import *
8 | from tqdm import tqdm
9 |
10 |
11 | # %% methods
12 | def get_var_name(var):
13 | local_vars = inspect.currentframe().f_back.f_locals.items()
14 | return [var_name for var_name, var_val in local_vars if var_val is var]
15 |
16 | def save_dataframes(dataframes: List):
17 | df_progress = tqdm(dataframes)
18 | for df in df_progress:
19 | df_name = df['name']
20 | df_progress.set_description('Saving: %s' % df_name)
21 | with open(DATA_DIR+DF_PREFIX+df_name+DF_EXT, 'wb') as out_file:
22 | pickle.dump(df, out_file)
23 |
24 | def get_dataframes(data_dir=DATA_DIR, prefix=DF_PREFIX, postfix = DF_EXT):
25 | dataframes_names = glob.glob(data_dir+prefix+'*'+postfix)
26 | df_progress = tqdm(dataframes_names)
27 | dataframes = {}
28 | for df in df_progress:
29 | with open(df, 'rb') as in_file:
30 | d = pickle.load(in_file)
31 | dataframes[d['name']] = d['data']
32 | return dataframes
33 |
34 | def get_html_base():
35 | base = '''
36 |
37 |
38 |
39 | {%metas%}
40 | {%title%}
41 | {%favicon%}
42 |
119 | {%css%}
120 |
121 |
122 | {%app_entry%}
123 |
124 | {%config%}
125 | {%scripts%}
126 | {%renderer%}
127 |
128 |
129 |
130 | '''
131 | return base
132 |
133 | # %%
134 |
--------------------------------------------------------------------------------
/reporting/reporter.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import argparse
3 | import glob
4 | import json
5 | import os
6 |
7 | import requests
8 | from jinja2 import Environment, FileSystemLoader
9 | from postman_reporter import (report_config, report_dashboard, report_data,
10 | report_static)
11 |
12 |
13 | def runData(args):
14 | def _json_from_url(url):
15 | return json.loads(requests.get(url).text)
16 |
17 | def _reports_from_url(url):
18 | def func():
19 | data = json.loads(requests.get(url).text)
20 | items = data["items"]
21 | report_sources = []
22 | for item in items:
23 | if ".json" in item:
24 | report_sources.append(item)
25 | return report_sources
26 |
27 | return func
28 |
29 | url = os.path.join(report_config.REPORTS_BASE_URL, args.type, "index.json")
30 |
31 | report_data.getData(
32 | get_reports=_reports_from_url(url),
33 | get_json=_json_from_url,
34 | )
35 |
36 | return 0
37 |
38 |
39 | def runDash():
40 | app = report_dashboard.getApp()
41 | print(app)
42 | app.run_server()
43 | return 0
44 |
45 |
46 | def runHtml(args):
47 | # Create the jinja2 environment.
48 | current_directory = os.path.dirname(os.path.abspath(__file__))
49 | env = Environment(loader=FileSystemLoader(current_directory))
50 | path = os.path.join("assets", f"{args.type}.j2")
51 | template = env.get_template(path)
52 | report_static.generate_html(template)
53 | return 0
54 |
55 |
56 | def runCi(args):
57 | """
58 | runCi prepares report data from local docs/reports folder and uses that
59 | data to generate a static interactive HTML report.
60 | """
61 |
62 | def _reports_from_file(path):
63 | def func():
64 | files = glob.glob(f"{path}/*.json")
65 | return [i for i in files if not i.endswith("index.json")]
66 |
67 | return func
68 |
69 | def _json_from_file(path):
70 | with open(path, "r") as fh:
71 | return json.load(fh)
72 |
73 | report_data.getData(
74 | get_reports=_reports_from_file(report_config.CI_DIR),
75 | get_json=_json_from_file,
76 | )
77 |
78 | runHtml(args)
79 |
80 |
81 | def main(args):
82 | # first check for data dir
83 | if not os.path.exists("./data"):
84 | os.mkdir(
85 | "./data"
86 | ) # explicitly let it throw an exception if permissions are not there
87 |
88 | # then for html
89 | if not os.path.exists("./html"):
90 | os.mkdir(
91 | "./html"
92 | ) # explicitly let it throw an exception if permissions are not there
93 |
94 | # now check args
95 | if args.mode == "all" or args.mode == "data":
96 | runData(args)
97 |
98 | if args.mode == "all" or args.mode == "html":
99 | runHtml(args)
100 |
101 | if args.mode == "all" or args.mode == "dashboard":
102 | runDash()
103 |
104 | if args.mode == "ci":
105 | runCi(args)
106 |
107 |
108 | if __name__ == "__main__":
109 | parser = argparse.ArgumentParser(
110 | description="Interop test results reporting utility"
111 | )
112 | parser.add_argument(
113 | "--mode",
114 | type=str,
115 | default="all",
116 | const="all",
117 | nargs="?",
118 | choices=["all", "data", "html", "dashboard", "ci"],
119 | help="mode to run the reporter in",
120 | )
121 |
122 | # Mutually-exclusive group must be nested in an argument group in order to
123 | # support providing a title and description in help output.
124 | group = parser.add_argument_group(
125 | "Report Type",
126 | "One of the following options MUST be specified.",
127 | )
128 | group = group.add_mutually_exclusive_group(required=True)
129 |
130 | group.add_argument(
131 | "-c",
132 | "--conformance",
133 | dest="type",
134 | action="store_const",
135 | const="conformance",
136 | help="generate a report based on the most recently published conformance testing output",
137 | )
138 |
139 | group.add_argument(
140 | "-i",
141 | "--interoperability",
142 | dest="type",
143 | action="store_const",
144 | const="interoperability",
145 | help="generate a report based on the most recently published interoperability testing output",
146 | )
147 |
148 | args = parser.parse_args()
149 | main(args)
150 |
--------------------------------------------------------------------------------
/reporting/requirements.txt:
--------------------------------------------------------------------------------
1 | Jinja2==3.1.2
2 | dash-bootstrap-components
3 | dash==2.3.1
4 | numpy==1.22.3
5 | pandas==1.4.2
6 | plotly==5.7.0
7 | requests==2.27.1
8 | tqdm==4.64.0
9 | urllib3==1.26.9
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | # Traceability API Conformance Testing
2 |
3 | The Postman suite in this directory is intended to test API implmentations for
4 | conformance against the published OpenAPI spec.
5 |
6 | Testing is performed by making requests to an endpoint and validating response
7 | bodies against configured schemas. Schemas are maintained in the Postman collection
8 | by the `update_conformance_schemas.sh` script, which is run by a workflow triggered
9 | by changes to files in the `docs/openapi` folder.
10 |
11 | Request bodies for the "Bad Request" series of negative tests for the `/credentials/verify` endpoint are generated using the `update_conformance_vcs.js` script. This will dynamically generate invalid credentials with valid signatures, and inject them directly into the Postman suite. Output is written to standard out, and should be redirected to a temporary file before overwriting the existing Postman suite, for example:
12 |
13 | ```bash
14 | ./update_conformance_vcs.js > tmp.json
15 | mv tmp.json conformance_suite.postman_collection.json
16 | ```
17 |
18 | ## Importing The Test Suite
19 |
20 | ### Create a workspace
21 |
22 | Postman test suites are imported into workspaces. You may either choose an existing workspace before importing, or create a new one by opening the "Workspaces" dropdown menu at the top left of the Postman window and clicking on the "Create Workspace" button.
23 |
24 |
25 |
26 | In the following examples, the "Traceability Conformance" workspace will be created and used.
27 |
28 |
29 |
30 | ### Import the collection
31 |
32 | Once you have created and/or selected your workspace, use the "Import" button to import the conformance collection.
33 |
34 |
35 |
36 | When the import modal window opens, select the "Link" option, paste the [link to the Postman collection](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/tests/conformance_suite.postman_collection.json) in the text input, and click "Continue"
37 |
38 |
39 |
40 | After you click "Continue", Postman will download and process the remote url and present a confirmation screen. Click the "Import" button to continue.
41 |
42 |
43 |
44 | ### Import the environment
45 |
46 | Use the "Import" button again to import the conformance environment.
47 |
48 |
49 |
50 | When the import modal window opens, select the "Link" option, paste the [link to the Postman environment](https://raw.githubusercontent.com/w3c-ccg/traceability-interop/main/tests/conformance_suite.postman_environment.json) in the text input, and click "Continue"
51 |
52 |
53 |
54 | After you click "Continue", Postman will download and process the remote url and present a confirmation screen. Click the "Import" button to continue.
55 |
56 |
57 |
58 | ### Configure the environment
59 |
60 | Once the environment finishes importing, you will need to add in the values specific to your implementation. Click on the "Environments" tab, then highlight the "Traceability Conformance" environment and update the values under the "INITIAL VALUE" column. Click "Reset All" to copy the values to the "CURRENT VALUE" column and then click "Save".
61 |
62 |
63 |
64 | You are now ready to begin executing conformance tests against your implementation!
65 |
66 | ## Testing Notes
67 |
68 | ### Optional Elements
69 | When a schema calls for optional elements, the base happy path test will exclude all optional items.
70 |
71 | There will be one additional happy path test for each optional item, which will be run separately.
72 |
73 | There will be one negative test for each optional item in which an invalid value will be used.
74 |
75 | ### Alternate Elements
76 | When a schema calls for one of several possible values for an item, the base happy path test will include testing for the first alternate. Additional happy path tests will be created for each of the remaining alternates.
77 |
78 | Negative tests will be created separately for each alternate item.
79 |
80 | ### Negative Type Checking
81 | Negative testing for type checking is exhaustive over javascript types, e.g., if a schema element is defined to be an array, the conformance suite will include one test for each of the other JS types (`boolean`, `integer`, `null`, `object`, and `string`) to ensure that the request fails.
82 |
83 | ### Negative Value Checking
84 | When a schema element is constrained to a specific set of values, negative testing will only check that the request fails for a single bad value. In this case, exhaustive testing is not feasible.
85 |
--------------------------------------------------------------------------------
/tests/conformance_suite.postman_environment.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "d7a28a8c-69bc-4df1-86f3-47376a3b7c68",
3 | "name": "Traceability Conformance",
4 | "values": [
5 | {
6 | "key": "API_BASE_URL",
7 | "value": "",
8 | "type": "default",
9 | "enabled": true
10 | },
11 | {
12 | "key": "CLIENT_ID",
13 | "value": "",
14 | "type": "default",
15 | "enabled": true
16 | },
17 | {
18 | "key": "CLIENT_SECRET",
19 | "value": "",
20 | "type": "secret",
21 | "enabled": true
22 | },
23 | {
24 | "key": "CLIENT_SCOPE",
25 | "value": "",
26 | "type": "default",
27 | "enabled": true
28 | },
29 | {
30 | "key": "ORGANIZATION_DID_WEB",
31 | "value": "",
32 | "type": "default",
33 | "enabled": true
34 | },
35 | {
36 | "key": "TOKEN_AUDIENCE",
37 | "value": "",
38 | "type": "default",
39 | "enabled": true
40 | },
41 | {
42 | "key": "TOKEN_ENDPOINT",
43 | "value": "",
44 | "type": "default",
45 | "enabled": true
46 | }
47 | ],
48 | "_postman_variable_scope": "environment",
49 | "_postman_exported_at": "2023-05-23T13:56:55.252Z",
50 | "_postman_exported_using": "Postman/9.31.29"
51 | }
--------------------------------------------------------------------------------
/tests/resources/configure-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/configure-environment.png
--------------------------------------------------------------------------------
/tests/resources/create-workspace-details.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/create-workspace-details.png
--------------------------------------------------------------------------------
/tests/resources/create-workspace-start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/create-workspace-start.png
--------------------------------------------------------------------------------
/tests/resources/import-collection-confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/import-collection-confirm.png
--------------------------------------------------------------------------------
/tests/resources/import-collection-link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/import-collection-link.png
--------------------------------------------------------------------------------
/tests/resources/import-environment-confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/import-environment-confirm.png
--------------------------------------------------------------------------------
/tests/resources/import-environment-link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/import-environment-link.png
--------------------------------------------------------------------------------
/tests/resources/import-start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/import-start.png
--------------------------------------------------------------------------------
/tests/resources/select-environment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c-ccg/traceability-interop/103073c6f132e5865805101842bdb7594a1b67ce/tests/resources/select-environment.png
--------------------------------------------------------------------------------
/tests/update_conformance_schemas.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # update_schemas.sh
4 | #
5 | #
6 |
7 | set -euo pipefail
8 |
9 | # Dereferenced JSON schema allows extraction of specific parts using jq
10 | SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )";
11 | YAML_SRC=`dirname "$SCRIPT_DIR"`/docs/openapi/openapi.yml
12 | JSON_SCHEMA=$(npx swagger-cli bundle "$YAML_SRC" --dereference)
13 |
14 | # update_postman injects schema into postman collection
15 | # $1 - Postman schema file
16 | # $2 - Postman collection variable name for schema
17 | # $3 - Stringified JSON schema to inject into Postman collection
18 | function update_postman() {
19 | FILE=$1; KEY=$2; SCHEMA=$3
20 | # Using a temp file (vs. in-place update) prevents truncation on failure
21 | TMP=$(mktemp)
22 | jq --arg k "$KEY" --arg s "$SCHEMA" --tab \
23 | '(.variable[] | select(.key==($k))).value=($s)' \
24 | "$FILE" > "$TMP" && mv "$TMP" "$FILE"
25 | }
26 |
27 | # get_schema extracts stringified JSON schema from openapi schema file
28 | # $1 - JQ selector string for the schema to extract
29 | function get_schema() {
30 | SCHEMA=$(echo $JSON_SCHEMA | jq -c $1)
31 | # Examples should be excluded from schema
32 | SCHEMA=$(echo $SCHEMA | jq -c 'del(..|.example?)')
33 | # JSON schema does not support "format" keyword for "integer" type
34 | SCHEMA=$(echo $SCHEMA | sed -e 's/,"format":"int32"//')
35 | echo $SCHEMA
36 | }
37 |
38 | # API Configuration [200]
39 | update_postman \
40 | "conformance_suite.postman_collection.json" \
41 | "responseSchema200ApiConfiguration" \
42 | "$(get_schema '.paths["/did.json"].get.responses["200"].content["application/json"].schema')"
43 |
44 | # Identifiers [200]
45 | update_postman \
46 | "conformance_suite.postman_collection.json" \
47 | "responseSchema200Identifiers" \
48 | "$(get_schema '.paths["/identifiers/{did}"].get.responses["200"].content["application/json"].schema')"
49 |
50 | # Identifiers [400]
51 | update_postman \
52 | "conformance_suite.postman_collection.json" \
53 | "responseSchema400Identifiers" \
54 | "$(get_schema '.paths["/identifiers/{did}"].get.responses["400"].content["application/json"].schema')"
55 |
56 | # Identifiers [404]
57 | update_postman \
58 | "conformance_suite.postman_collection.json" \
59 | "responseSchema404" \
60 | "$(get_schema '.paths["/identifiers/{did}"].get.responses["404"].content["application/json"].schema')"
61 |
62 | # Credentials - Issue [201]
63 | update_postman \
64 | "conformance_suite.postman_collection.json" \
65 | "responseSchema201CredentialsIssue" \
66 | "$(get_schema '.paths["/credentials/issue"].post.responses["201"].content["application/json"].schema')"
67 |
68 | # Credentials - Issue [400]
69 | update_postman \
70 | "conformance_suite.postman_collection.json" \
71 | "responseSchema400" \
72 | "$(get_schema '.paths["/credentials/issue"].post.responses["400"].content["application/json"].schema')"
73 |
74 | # Credentials - Issue [401]
75 | update_postman \
76 | "conformance_suite.postman_collection.json" \
77 | "responseSchema401" \
78 | "$(get_schema '.paths["/credentials/issue"].post.responses["401"].content["application/json"].schema')"
79 |
80 | # Credentials - Issue [403]
81 | update_postman \
82 | "conformance_suite.postman_collection.json" \
83 | "responseSchema403" \
84 | "$(get_schema '.paths["/credentials/issue"].post.responses["403"].content["application/json"].schema')"
85 |
86 | # Credentials - Issue [422]
87 | update_postman \
88 | "conformance_suite.postman_collection.json" \
89 | "responseSchema422CredentialsIssue" \
90 | "$(get_schema '.paths["/credentials/issue"].post.responses["422"].content["application/json"].schema')"
91 |
92 | # Credentials - Issue [500]
93 | update_postman \
94 | "conformance_suite.postman_collection.json" \
95 | "responseSchema500" \
96 | "$(get_schema '.paths["/credentials/issue"].post.responses["500"].content["application/json"].schema')"
97 |
98 | # Credentials - Verify [200]
99 | update_postman \
100 | "conformance_suite.postman_collection.json" \
101 | "responseSchema200CredentialsVerify" \
102 | "$(get_schema '.paths["/credentials/verify"].post.responses["200"].content["application/json"].schema')"
103 |
--------------------------------------------------------------------------------
/tests/valid-credential.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": ["https://www.w3.org/2018/credentials/v1", "https://w3id.org/traceability/v1"],
3 | "credentialSubject": {
4 | "id": "did:example:123"
5 | },
6 | "id": "urn:uuid:57016a7f-0e4c-4be9-beec-cf39c4dd459a",
7 | "issuanceDate": "2006-01-02T15:04:05Z",
8 | "issuer": "did:key:z6MkgVHZNqLBqoQAoGxRiSJP5gLgVEDCJJzT5ZsGEabKtfyn",
9 | "type": ["VerifiableCredential"]
10 | }
11 |
--------------------------------------------------------------------------------