mirror of
https://github.com/trailofbits/buttercup
synced 2026-06-21 14:11:39 +00:00
Update apis (#526)
* Update apis Closes #436 Updates APIs to 1.2-rc1 ahead of unscored round 2 * Update values.yaml * Bump competition/crs API to v1.2 * Breaking changes in competition api config * Check for SARIFs in CI (#527) * Check for SARIFs in CI * Remove trailing bracket --------- Co-authored-by: Henrik Brodin <90325907+hbrodin@users.noreply.github.com>
This commit is contained in:
@@ -34,12 +34,17 @@ on:
|
||||
description: "Timeout for bundle submission in minutes"
|
||||
required: false
|
||||
default: ""
|
||||
sarif_timeout:
|
||||
description: "Timeout for SARIF submission in minutes"
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
env:
|
||||
FUZZER_BUILD_TIMEOUT: ${{ inputs.build_timeout || 20 }}
|
||||
VULN_TIMEOUT: ${{ inputs.vuln_timeout || 25 }}
|
||||
PATCH_TIMEOUT: ${{ inputs.patch_timeout || 15 }}
|
||||
BUNDLE_TIMEOUT: ${{ inputs.bundle_timeout || 5 }}
|
||||
SARIF_TIMEOUT: ${{ inputs.sarif_timeout || 5 }}
|
||||
FUZZ_TOOLING_CONTAINER_ORG: ${{ inputs.fuzz_tooling_container_org || 'aixcc-afc' }}
|
||||
|
||||
permissions:
|
||||
@@ -175,6 +180,27 @@ jobs:
|
||||
while ! kubectl logs -n $BUTTERCUP_NAMESPACE -l app=scheduler | grep "SUBMIT_BUNDLE -> SUBMIT_MATCHING_SARIF"; do
|
||||
sleep 10
|
||||
done
|
||||
- name: Send a SARIF broadcast
|
||||
timeout-minutes: ${{ fromJSON(env.SARIF_TIMEOUT) }}
|
||||
run: |
|
||||
TASK_ID=$(kubectl logs -n $BUTTERCUP_NAMESPACE -l app=scheduler | grep "SUBMIT_BUNDLE -> SUBMIT_MATCHING_SARIF" | grep -o "\[[^]]*\]" | grep -o "[^[]*$" | cut -d: -f2 | tr -d ']')
|
||||
echo "Task ID: $TASK_ID"
|
||||
kubectl port-forward -n $BUTTERCUP_NAMESPACE service/buttercup-competition-api 31323:1323 &
|
||||
sleep 5
|
||||
./orchestrator/scripts/send_sarif.sh $TASK_ID
|
||||
sleep 5
|
||||
- name: Wait for SARIF to be submitted as correct
|
||||
timeout-minutes: ${{ fromJSON(env.SARIF_TIMEOUT) }}
|
||||
run: |
|
||||
while ! kubectl logs -n $BUTTERCUP_NAMESPACE -l app=scheduler | grep "SUBMIT_MATCHING_SARIF -> SUBMIT_BUNDLE_PATCH"; do
|
||||
sleep 10
|
||||
done
|
||||
- name: Wait for Bundle to be patched to include the SARIF
|
||||
timeout-minutes: ${{ fromJSON(env.SARIF_TIMEOUT) }}
|
||||
run: |
|
||||
while ! kubectl logs -n $BUTTERCUP_NAMESPACE -l app=scheduler | grep "SUBMIT_BUNDLE_PATCH -> STOP"; do
|
||||
sleep 10
|
||||
done
|
||||
# TODO: re-enable seed-gen once it's fixed
|
||||
# - name: Wait for seed-gen to find PoV
|
||||
# timeout-minutes: 10 # low timeout because already waiting for prior steps
|
||||
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
# - shared-tmp:/tmp
|
||||
|
||||
scantron:
|
||||
image: ghcr.io/aixcc-finals/example-crs-architecture/competition-test-api:v1.1-rc7
|
||||
image: ghcr.io/aixcc-finals/example-crs-architecture/competition-test-api:v1.2-rc1
|
||||
platform: linux/amd64
|
||||
privileged: true
|
||||
volumes:
|
||||
|
||||
@@ -39,3 +39,12 @@ api_host_and_port: "scantron:31323"
|
||||
# # github Personal Access token. This is used by the server to download the
|
||||
# # appropriate fuzz tooling if not using public repositories
|
||||
# pat: ghp_XXXXXXXXXXXXXXXXXXXXX
|
||||
generate:
|
||||
enabled: true
|
||||
delta:
|
||||
repo_url: "https://github.com/aixcc-finals/integration-test.git"
|
||||
base_ref: "5ac0917575e20464b5aa86434dff2a7626b558b4"
|
||||
head_ref: "challenges/integration-test-delta-01"
|
||||
fuzz_tooling_url: "https://github.com/aixcc-finals/oss-fuzz-aixcc.git"
|
||||
fuzz_tooling_ref: "v1.1.0"
|
||||
fuzz_tooling_project_name: "integration-test"
|
||||
@@ -37,3 +37,12 @@ data:
|
||||
listen_address: "[::]:1323"
|
||||
api_host_and_port: "{{ .Release.Name }}-competition-api.{{ .Release.Namespace }}.svc.cluster.local:1323"
|
||||
{{- end }}
|
||||
generate:
|
||||
enabled: true
|
||||
delta:
|
||||
repo_url: "https://github.com/aixcc-finals/integration-test.git"
|
||||
base_ref: "5ac0917575e20464b5aa86434dff2a7626b558b4"
|
||||
head_ref: "challenges/integration-test-delta-01"
|
||||
fuzz_tooling_url: "https://github.com/aixcc-finals/oss-fuzz-aixcc.git"
|
||||
fuzz_tooling_ref: "v1.1.0"
|
||||
fuzz_tooling_project_name: "integration-test"
|
||||
|
||||
@@ -30,7 +30,7 @@ global:
|
||||
pullSecrets: ["ghcr-auth"]
|
||||
competitionApiImage:
|
||||
repository: ghcr.io/aixcc-finals/example-crs-architecture/competition-test-api
|
||||
tag: v1.1-rc7
|
||||
tag: v1.2-rc1
|
||||
pullPolicy: Always
|
||||
pullSecrets: ["ghcr-auth"]
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# AIxCC Final Documentation
|
||||
|
||||
Welcome to the documentation page for the AIxCC Final Competition.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Changelog](api/CHANGELOG.md#changelog)
|
||||
- [1.2.0](api/CHANGELOG.md#120)
|
||||
- [v1.1.1](api/CHANGELOG.md#v111)
|
||||
- [v1.1](api/CHANGELOG.md#v11)
|
||||
- [v1.0](api/CHANGELOG.md#v10)
|
||||
- [v0.4](api/CHANGELOG.md#v04)
|
||||
- [v0.3](api/CHANGELOG.md#v03)
|
||||
- [API](api/README.md#api)
|
||||
- [Competition API Interaction](api/README.md#competition-api-interaction)
|
||||
- [Submitting a vulnerability](api/README.md#submitting-a-vulnerability)
|
||||
- [Submitting a SARIF assessment](api/README.md#submitting-a-sarif-assessment)
|
||||
- [Submitting a patch](api/README.md#submitting-a-patch)
|
||||
- [Submitting a bundle](api/README.md#submitting-a-bundle)
|
||||
- [Request Integration Test Task](api/README.md#request-integration-test-task)
|
||||
- [CRS API Task Statuses](api/README.md#crs-api-task-statuses)
|
||||
- [Generating a Client or Server](api/README.md#generating-a-client-or-server)
|
||||
- [OpenAPI Generator](api/README.md#openapi-generator)
|
||||
- [Viewing the UI](api/README.md#viewing-the-ui)
|
||||
- [CRS Telemetry Specification v1.0](telemetry/README.md#crs-telemetry-specification-v10)
|
||||
- [GenAI (LLM requests and responses)](telemetry/README.md#genai-llm-requests-and-responses)
|
||||
- [CRS Actions](telemetry/README.md#crs-actions)
|
||||
- [Resource Attributes](telemetry/README.md#resource-attributes)
|
||||
- [Mandatory Span Attributes](telemetry/README.md#mandatory-span-attributes)
|
||||
- [Optional Attributes](telemetry/README.md#optional-attributes)
|
||||
- [Specialized Attributes for LLM Requests](telemetry/README.md#specialized-attributes-for-llm-requests)
|
||||
- [Specialized Attributes for Fuzzing](telemetry/README.md#specialized-attributes-for-fuzzing)
|
||||
- [Example Python Implementation](telemetry/README.md#example-python-implementation)
|
||||
- [Alternative Python Implementation](telemetry/README.md#alternative-python-implementation)
|
||||
- [Example CRS Webservice](telemetry/README.md#example-crs-webservice)
|
||||
- [Other Usage Examples](telemetry/README.md#other-usage-examples)
|
||||
- [General telemetry guidance](telemetry/telemetry_best_practices.md#general-telemetry-guidance)
|
||||
- [Improving the structure of OTEL data](telemetry/telemetry_best_practices.md#improving-the-structure-of-otel-data)
|
||||
- [Verifying telemetry](telemetry/telemetry_best_practices.md#verifying-telemetry)
|
||||
- [Tailnet-accessible hosted Competitor Test Server](tailscale-hosted-competitor-test-server/hosted_competitor_test_server.md#tailnet-accessible-hosted-competitor-test-server)
|
||||
- [Tailscale Management Tools](tailscale-hosted-competitor-test-server/tailscale_management_tools.md#tailscale-management-tools)
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
## Enum
|
||||
|
||||
* `X86_64` (value: `'x86_64'`)
|
||||
* `ArchitectureX8664` (value: `'x86_64'`)
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
## Enum
|
||||
|
||||
* `CORRECT` (value: `'correct'`)
|
||||
* `AssessmentCorrect` (value: `'correct'`)
|
||||
|
||||
* `INCORRECT` (value: `'incorrect'`)
|
||||
* `AssessmentIncorrect` (value: `'incorrect'`)
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
## Enum
|
||||
|
||||
* `ACCEPTED` (value: `'accepted'`)
|
||||
* `SubmissionStatusAccepted` (value: `'accepted'`)
|
||||
|
||||
* `PASSED` (value: `'passed'`)
|
||||
* `SubmissionStatusPassed` (value: `'passed'`)
|
||||
|
||||
* `FAILED` (value: `'failed'`)
|
||||
* `SubmissionStatusFailed` (value: `'failed'`)
|
||||
|
||||
* `DEADLINE_EXCEEDED` (value: `'deadline_exceeded'`)
|
||||
* `SubmissionStatusDeadlineExceeded` (value: `'deadline_exceeded'`)
|
||||
|
||||
* `ERRORED` (value: `'errored'`)
|
||||
* `SubmissionStatusErrored` (value: `'errored'`)
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## 1.2.0
|
||||
|
||||
- revert to the default SARIF schema removing the required property on `ruleId`
|
||||
- add endpoint for requesting an integration test challenge
|
||||
|
||||
## v1.1.1
|
||||
|
||||
- correct typo in swagger docs tags for freeform submission
|
||||
@@ -40,8 +45,7 @@ For more information, see:
|
||||
- Added optional `sarif_id` on patch submissions
|
||||
- Added large max sizes to most string fields on the Competition API
|
||||
- Added note that max sizes for base64 fields are before encoding
|
||||
- Added metadata fields to Task and SARIF broadcasts containing a string to string map that should be attached
|
||||
to outputs like log messages and OpenTelemetry trace attributes for traceability
|
||||
- Added metadata fields to Task and SARIF broadcasts containing a string to string map that should be attached to outputs like log messages and OpenTelemetry trace attributes for traceability
|
||||
- Added `focus` and `project_name` to Task broadcasts.
|
||||
- Project name is the OSS Fuzz project name for the task.
|
||||
- Focus is the name of the directory in the `repo` tarball that vulns, patches, and SARIF broadcasts should be submitted against.
|
||||
|
||||
@@ -1,47 +1,12 @@
|
||||
# API
|
||||
|
||||
See the [API Changelog](./docs/api/CHANGELOG.md) for information on recent API changes.
|
||||
See the [API Changelog](./CHANGELOG.md) for information on recent API changes.
|
||||
|
||||
- Competitors will consume the API described by `competition-swagger-v1.1.1.yaml`
|
||||
- Competitors will provide the API described by `crs-swagger-v1.1.yaml`
|
||||
- Competitors will consume the API described by `competition-swagger.yaml`
|
||||
- Competitors will provide the API described by `crs-swagger.yaml`
|
||||
|
||||
NOTE: The JSON and YAML documents contain the same information and are generated from the same source.
|
||||
|
||||
These files describe the CRS API and the Example Competition API. [Swagger](https://swagger.io/blog/api-strategy/difference-between-swagger-and-openapi/) is an ecosystem built around the [OpenAPI](https://www.openapis.org/what-is-openapi)
|
||||
specification with which it is possible to render a UI documenting the API, to generate client code to interact with the API, and to generate
|
||||
server code to be the API. In essence, the OpenAPI specification is a standard way of documenting HTTP APIs. This allows tools built to consume the description
|
||||
to be portable across APIs.
|
||||
|
||||
The different components can be used as needed for different applications. The Example Competition API specification
|
||||
is generated using inline code comments and served under the `/swagger/` path. A web framework specific third-party dependency that included the
|
||||
swagger-ui was used to provide the endpoints.
|
||||
|
||||
## Viewing the UI
|
||||
|
||||
The provided Example Competition API will serve the swagger UI at `/swagger/index.html`. The spec is served at `/swagger/doc.json`
|
||||
Competitors may find it useful to do something similar for their CRS.
|
||||
|
||||
Most webserver frameworks will have a package that can be used to help serve the UI. If this is not possible or you do not wish to use a third-party package,
|
||||
the source can be downloaded from [https://github.com/swagger-api/swagger-ui/releases](https://github.com/swagger-api/swagger-ui/releases).
|
||||
After unpacking the archive using tar or ZIP, the precompiled source can be found in the `dist` directory.
|
||||
|
||||
If you do not wish to integrate the UI directly into the CRS system it is still possible to use for development.
|
||||
|
||||
- Using the same method described above, download and unpack the release.
|
||||
- Place any number of swagger specs inside the `swagger-ui/dist` folder.
|
||||
- Start a basic webserver from the `swagger-ui/dist` folder. For example the built-in Python 3 webserver:
|
||||
|
||||
```bash
|
||||
# PWD: swagger-ui/dist
|
||||
python -m http.server
|
||||
```
|
||||
|
||||
- Change the path to the swagger file at the top of your page to the desired file. For example, `/competition-swagger-v0.1.json` if you placed
|
||||
a swagger spec called `competition-swagger-v0.1.json` at `swagger-ui/dist/competition-swagger-v0.1.json`.
|
||||
- This will only allow viewing the documentation. Experimenting with the API endpoints requires a running API server serving the spec file.
|
||||
If the spec is served from the API server and it supports CORS, it is possible to specify the full URL to the spec in the box.
|
||||
This will allow you to experiment with the API using the `Try it Out` button.
|
||||
|
||||
## Competition API Interaction
|
||||
|
||||
During the competition, the Competition API sends tasks and SARIF broadcasts to CRSs and receives responses of several types (vulnerability, patch, or SARIF assessment). The Example Competition API checks interfaces
|
||||
@@ -106,6 +71,29 @@ CRS->>API: Create Bundle "accepted"
|
||||
CRS->>API: Modify Bundle
|
||||
```
|
||||
|
||||
### Request Integration Test Task
|
||||
|
||||
After deploying your CRS, you now have the ability to task your CRS with a simple “[integration test](https://github.com/aixcc-finals/integration-test/tree/challenges/integration-test-delta-01)” challenge (delta scan) to
|
||||
make sure your CRS and Telemetry are working as expected prior to the opening of the Round.
|
||||
|
||||
This endpoint is available from now until 5 minutes prior to the opening of a Round. It is accessible from the internet and from inside the tailnet. `duration_secs` is an optional parameter, and defaults to 4 hours.
|
||||
Provide your Competition API credentials to kick off the task. This will send a task to the Round's expected CRS hostname (e.g. `team-moniker-exhibition2` for exhibition2) on the tailnet.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
accTitle: Smoke Test Workflow
|
||||
|
||||
User->>API: /v1/request/delta
|
||||
API->>CRS: Hardcoded integration-test task
|
||||
CRS->>API: POV/Patch/Bundle/Sarif Submission
|
||||
```
|
||||
|
||||
Here is an example curl you may use to trigger the integration testing task.
|
||||
|
||||
```bash
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X 'POST' 'https://api.aixcc.tech/v1/request/delta/' -H 'Content-Type: application/json' -d '{"duration_secs": 3600 }'
|
||||
```
|
||||
|
||||
## CRS API Task Statuses
|
||||
|
||||
The CRS API has a status endpoint which provides a summary of tasks by status, among other things. The statuses which tasks go through are documented in the state diagram below.
|
||||
@@ -127,12 +115,13 @@ stateDiagram-v2
|
||||
|
||||
## Generating a Client or Server
|
||||
|
||||
It is possible to generate client or server code from the swagger documents. The documents are a best effort to provide a strongly typed schema but are not perfect.
|
||||
Use the generators at your own discretion as they are not maintained by AIxCC and may not produce working code.
|
||||
It is possible to generate client or server code from the swagger documents. The documents are a best effort to provide a strongly typed schema but are not perfect. Use the generators at your own discretion as they are
|
||||
not maintained by AIxCC and may not produce working code.
|
||||
|
||||
### OpenAPI Generator
|
||||
|
||||
OpenAPI generator is a fork and actively maintained continuation of the swagger-codegen project. The source code can be found here: [https://github.com/openapitools/openapi-generator](https://github.com/openapitools/openapi-generator).
|
||||
OpenAPI generator is a fork and actively maintained continuation of the swagger-codegen project. The source code can be found here:
|
||||
[https://github.com/openapitools/openapi-generator](https://github.com/openapitools/openapi-generator).
|
||||
|
||||
To run the generator using docker or podman:
|
||||
|
||||
@@ -143,18 +132,49 @@ docker run --rm -v $PWD:/local openapitools/openapi-generator-cli generate \
|
||||
-o /local/out
|
||||
```
|
||||
|
||||
- `-v $PWD:/local` mounts the current working directory into the `/local` directory in the container.
|
||||
A different host path could be provided for `$PWD`. All paths used in the following steps would be relative to the new path instead of `$PWD`.
|
||||
- `-v $PWD:/local` mounts the current working directory into the `/local` directory in the container. A different host path could be provided for `$PWD`. All paths used in the following steps would be relative to the new
|
||||
path instead of `$PWD`.
|
||||
- All arguments after `openapitools/openapi-generator-cli` are passed to the generator CLI inside the container
|
||||
- `-i /local/competition-swagger-v0.1.json` is the path relative to the current working directory of the swagger file. On the host, `competition-swagger-v-0.1.json` is located in `$PWD`.
|
||||
If you want to change the file or path it must be a descendant of `$PWD`.
|
||||
- `-i /local/competition-swagger-v0.1.json` is the path relative to the current working directory of the swagger file. On the host, `competition-swagger-v-0.1.json` is located in `$PWD`. If you want to change the file or
|
||||
path it must be a descendant of `$PWD`.
|
||||
- `-g lang` is used to specify the generator to run. If you pass an invalid value it will list all of the options.
|
||||
- `-o /local/out` is the path relative to the current working directory to output the generated code.
|
||||
- A language specific config file can be optionally provided using `-c /local/path_to_config` [Project Docs](https://github.com/OpenAPITools/openapi-generator/blob/b218e238f4f6cac8c919a78b296d3062bdfec0be/docs/customization.md#customizing-the-generator).
|
||||
The available config options can be found using the `config-help -g lang` subcommand instead of `generate`.
|
||||
- A language specific config file can be optionally provided using `-c /local/path_to_config`
|
||||
[Project Docs](https://github.com/OpenAPITools/openapi-generator/blob/b218e238f4f6cac8c919a78b296d3062bdfec0be/docs/customization.md#customizing-the-generator). The available config options can be found using the
|
||||
`config-help -g lang` subcommand instead of `generate`.
|
||||
|
||||
To see all available options for the generate command:
|
||||
|
||||
```bash
|
||||
docker run --rm -v $PWD:/local openapitools/openapi-generator-cli help generate
|
||||
```
|
||||
|
||||
### Viewing the UI
|
||||
|
||||
The swagger documents describe the CRS API and the Example Competition API. [Swagger](https://swagger.io/blog/api-strategy/difference-between-swagger-and-openapi/) is an ecosystem built around the
|
||||
[OpenAPI](https://www.openapis.org/what-is-openapi) specification with which it is possible to render a UI documenting the API, to generate client code to interact with the API, and to generate server code to be the API.
|
||||
In essence, the OpenAPI specification is a standard way of documenting HTTP APIs. This allows tools built to consume the description to be portable across APIs.
|
||||
|
||||
The different components can be used as needed for different applications. The Example Competition API specification is generated using inline code comments and served under the `/swagger/` path. A web framework specific
|
||||
third-party dependency that included the swagger-ui was used to provide the endpoints.
|
||||
|
||||
The provided Example Competition API will serve the swagger UI at `/swagger/index.html`. The spec is served at `/swagger/doc.json` Competitors may find it useful to do something similar for their CRS.
|
||||
|
||||
Most webserver frameworks will have a package that can be used to help serve the UI. If this is not possible or you do not wish to use a third-party package, the source can be downloaded from
|
||||
[https://github.com/swagger-api/swagger-ui/releases](https://github.com/swagger-api/swagger-ui/releases). After unpacking the archive using tar or ZIP, the precompiled source can be found in the `dist` directory.
|
||||
|
||||
If you do not wish to integrate the UI directly into the CRS system it is still possible to use for development.
|
||||
|
||||
- Using the same method described above, download and unpack the release.
|
||||
- Place any number of swagger specs inside the `swagger-ui/dist` folder.
|
||||
- Start a basic webserver from the `swagger-ui/dist` folder. For example the built-in Python 3 webserver:
|
||||
|
||||
```bash
|
||||
# PWD: swagger-ui/dist
|
||||
python -m http.server
|
||||
```
|
||||
|
||||
- Change the path to the swagger file at the top of your page to the desired file. For example, `/competition-swagger-v0.1.json` if you placed a swagger spec called `competition-swagger-v0.1.json` at
|
||||
`swagger-ui/dist/competition-swagger-v0.1.json`.
|
||||
- This will only allow viewing the documentation. Experimenting with the API endpoints requires a running API server serving the spec file. If the spec is served from the API server and it supports CORS, it is possible
|
||||
to specify the full URL to the spec in the box. This will allow you to experiment with the API using the `Try it Out` button.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,860 @@
|
||||
definitions:
|
||||
types.Architecture:
|
||||
enum:
|
||||
- x86_64
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- ArchitectureX8664
|
||||
types.Assessment:
|
||||
enum:
|
||||
- correct
|
||||
- incorrect
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- AssessmentCorrect
|
||||
- AssessmentIncorrect
|
||||
types.BundleSubmission:
|
||||
properties:
|
||||
broadcast_sarif_id:
|
||||
format: uuid
|
||||
type: string
|
||||
description:
|
||||
description:
|
||||
optional plaintext description of the components of the bundle,
|
||||
such as would be found in a pull request description or bug report
|
||||
type: string
|
||||
freeform_id:
|
||||
format: uuid
|
||||
type: string
|
||||
patch_id:
|
||||
format: uuid
|
||||
type: string
|
||||
pov_id:
|
||||
format: uuid
|
||||
type: string
|
||||
submitted_sarif_id:
|
||||
format: uuid
|
||||
type: string
|
||||
type: object
|
||||
types.BundleSubmissionResponse:
|
||||
properties:
|
||||
bundle_id:
|
||||
format: uuid
|
||||
type: string
|
||||
status:
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.SubmissionStatus"
|
||||
description:
|
||||
Schema-compliant submissions will only ever receive the statuses
|
||||
accepted or deadline_exceeded
|
||||
required:
|
||||
- bundle_id
|
||||
- status
|
||||
type: object
|
||||
types.BundleSubmissionResponseVerbose:
|
||||
properties:
|
||||
broadcast_sarif_id:
|
||||
format: uuid
|
||||
type: string
|
||||
bundle_id:
|
||||
format: uuid
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
freeform_id:
|
||||
format: uuid
|
||||
type: string
|
||||
patch_id:
|
||||
format: uuid
|
||||
type: string
|
||||
pov_id:
|
||||
format: uuid
|
||||
type: string
|
||||
status:
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.SubmissionStatus"
|
||||
description:
|
||||
Schema-compliant submissions will only ever receive the statuses
|
||||
accepted or deadline_exceeded
|
||||
submitted_sarif_id:
|
||||
format: uuid
|
||||
type: string
|
||||
required:
|
||||
- bundle_id
|
||||
- status
|
||||
type: object
|
||||
types.Error:
|
||||
properties:
|
||||
fields:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
message:
|
||||
type: string
|
||||
required:
|
||||
- message
|
||||
type: object
|
||||
types.FreeformResponse:
|
||||
properties:
|
||||
freeform_id:
|
||||
format: uuid
|
||||
type: string
|
||||
status:
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.SubmissionStatus"
|
||||
description:
|
||||
Schema-compliant submissions will only ever receive the statuses
|
||||
accepted or deadline_exceeded
|
||||
required:
|
||||
- freeform_id
|
||||
- status
|
||||
type: object
|
||||
types.FreeformSubmission:
|
||||
properties:
|
||||
submission:
|
||||
description: |-
|
||||
Base64 encoded arbitrary data
|
||||
|
||||
2MiB max size before Base64 encoding
|
||||
type: string
|
||||
required:
|
||||
- submission
|
||||
type: object
|
||||
types.POVSubmission:
|
||||
properties:
|
||||
architecture:
|
||||
$ref: "#/definitions/types.Architecture"
|
||||
engine:
|
||||
description: |-
|
||||
Fuzz Tooling Engine that exercises this vuln. Allowable engine values are specified in project.yaml.
|
||||
|
||||
4KiB max size
|
||||
maxLength: 4096
|
||||
type: string
|
||||
fuzzer_name:
|
||||
description: |-
|
||||
Fuzz Tooling fuzzer that exercises this vuln
|
||||
|
||||
4KiB max size
|
||||
maxLength: 4096
|
||||
type: string
|
||||
sanitizer:
|
||||
description: |-
|
||||
Fuzz Tooling Sanitizer that exercises this vuln
|
||||
|
||||
4KiB max size
|
||||
maxLength: 4096
|
||||
type: string
|
||||
testcase:
|
||||
description: |-
|
||||
Base64 encoded vuln trigger
|
||||
|
||||
2MiB max size before Base64 encoding
|
||||
format: base64
|
||||
type: string
|
||||
required:
|
||||
- architecture
|
||||
- engine
|
||||
- fuzzer_name
|
||||
- sanitizer
|
||||
- testcase
|
||||
type: object
|
||||
types.POVSubmissionResponse:
|
||||
properties:
|
||||
pov_id:
|
||||
format: uuid
|
||||
type: string
|
||||
status:
|
||||
$ref: "#/definitions/types.SubmissionStatus"
|
||||
required:
|
||||
- pov_id
|
||||
- status
|
||||
type: object
|
||||
types.PatchSubmission:
|
||||
properties:
|
||||
patch:
|
||||
description: |-
|
||||
Base64 encoded patch in unified diff format
|
||||
|
||||
100KiB max size before Base64 encoding
|
||||
format: base64
|
||||
type: string
|
||||
required:
|
||||
- patch
|
||||
type: object
|
||||
types.PatchSubmissionResponse:
|
||||
properties:
|
||||
functionality_tests_passing:
|
||||
description: null indicates the tests have not been run
|
||||
type: boolean
|
||||
patch_id:
|
||||
format: uuid
|
||||
type: string
|
||||
status:
|
||||
$ref: "#/definitions/types.SubmissionStatus"
|
||||
required:
|
||||
- patch_id
|
||||
- status
|
||||
type: object
|
||||
types.PingResponse:
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
type: object
|
||||
types.RequestSubmission:
|
||||
properties:
|
||||
duration_secs:
|
||||
description:
|
||||
Time in seconds until a task should expire. If not provided,
|
||||
defaults to 3600.
|
||||
type: integer
|
||||
type: object
|
||||
types.SARIFSubmission:
|
||||
properties:
|
||||
sarif:
|
||||
description: SARIF object compliant with the provided schema
|
||||
type: object
|
||||
required:
|
||||
- sarif
|
||||
type: object
|
||||
types.SARIFSubmissionResponse:
|
||||
properties:
|
||||
status:
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.SubmissionStatus"
|
||||
description:
|
||||
Schema-compliant submissions will only ever receive the statuses
|
||||
accepted or deadline_exceeded
|
||||
submitted_sarif_id:
|
||||
format: uuid
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- submitted_sarif_id
|
||||
type: object
|
||||
types.SarifAssessmentResponse:
|
||||
properties:
|
||||
status:
|
||||
$ref: "#/definitions/types.SubmissionStatus"
|
||||
required:
|
||||
- status
|
||||
type: object
|
||||
types.SarifAssessmentSubmission:
|
||||
properties:
|
||||
assessment:
|
||||
$ref: "#/definitions/types.Assessment"
|
||||
description:
|
||||
description: |-
|
||||
Plain text reasoning for the assessment
|
||||
|
||||
128KiB max size
|
||||
maxLength: 131072
|
||||
type: string
|
||||
required:
|
||||
- assessment
|
||||
- description
|
||||
type: object
|
||||
types.SubmissionStatus:
|
||||
enum:
|
||||
- accepted
|
||||
- passed
|
||||
- failed
|
||||
- deadline_exceeded
|
||||
- errored
|
||||
type: string
|
||||
x-enum-comments:
|
||||
SubmissionStatusAccepted: Successfully submitted
|
||||
SubmissionStatusDeadlineExceeded:
|
||||
Task deadline exceeded. All submissions marked
|
||||
accepted before the deadline will be evaluated.
|
||||
SubmissionStatusErrored: Server side error when testing submission
|
||||
SubmissionStatusFailed: Submission failed testing
|
||||
SubmissionStatusPassed: Successfully evaluated submission
|
||||
x-enum-varnames:
|
||||
- SubmissionStatusAccepted
|
||||
- SubmissionStatusPassed
|
||||
- SubmissionStatusFailed
|
||||
- SubmissionStatusDeadlineExceeded
|
||||
- SubmissionStatusErrored
|
||||
info:
|
||||
contact: {}
|
||||
title: Example Competition API
|
||||
version: 1.2.0
|
||||
paths:
|
||||
/v1/ping/:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Test authentication creds and network connectivity
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.PingResponse"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Test authentication creds and network connectivity
|
||||
tags:
|
||||
- ping
|
||||
/v1/request/delta/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Send a delta task to the source of this request
|
||||
parameters:
|
||||
- description: Submission Body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.RequestSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: No Content
|
||||
schema:
|
||||
type: string
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Send a delta task to the source of this request
|
||||
tags:
|
||||
- request
|
||||
/v1/task/{task_id}/broadcast-sarif-assessment/{broadcast_sarif_id}/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Submit a SARIF assessment
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Broadcast SARIF ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: broadcast_sarif_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Submission body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.SarifAssessmentSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.SarifAssessmentResponse"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Submit a SARIF Assessment
|
||||
tags:
|
||||
- broadcast-sarif-assessment
|
||||
/v1/task/{task_id}/bundle/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: submits a bundle
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Submission Body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.BundleSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.BundleSubmissionResponse"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Submit Bundle
|
||||
tags:
|
||||
- bundle
|
||||
/v1/task/{task_id}/bundle/{bundle_id}/:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: delete a bundle
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Bundle ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: bundle_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
schema:
|
||||
type: string
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Delete Bundle
|
||||
tags:
|
||||
- bundle
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: get a bundle
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Bundle ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: bundle_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.BundleSubmissionResponseVerbose"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Get Bundle
|
||||
tags:
|
||||
- bundle
|
||||
patch:
|
||||
consumes:
|
||||
- application/json
|
||||
description: updates a bundle
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Bundle ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: bundle_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Submission Body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.BundleSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.BundleSubmissionResponseVerbose"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Update Bundle
|
||||
tags:
|
||||
- bundle
|
||||
/v1/task/{task_id}/freeform/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: submits a freeform pov
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Submission Body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.FreeformSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.FreeformResponse"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Submit Freeform
|
||||
tags:
|
||||
- freeform
|
||||
/v1/task/{task_id}/patch/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: submit a patch for testing
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Payload
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.PatchSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.PatchSubmissionResponse"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Submit Patch
|
||||
tags:
|
||||
- patch
|
||||
/v1/task/{task_id}/patch/{patch_id}/:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: yield the status of patch testing
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Patch ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: patch_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.PatchSubmissionResponse"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Patch Status
|
||||
tags:
|
||||
- patch
|
||||
/v1/task/{task_id}/pov/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: submit a vulnerability for testing
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Submission body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.POVSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.POVSubmissionResponse"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Submit Vulnerability
|
||||
tags:
|
||||
- pov
|
||||
/v1/task/{task_id}/pov/{pov_id}/:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: yield the status of vuln testing
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: POV ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: pov_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.POVSubmissionResponse"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Vulnerability Status
|
||||
tags:
|
||||
- pov
|
||||
/v1/task/{task_id}/submitted-sarif/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Submit a CRS generated SARIF
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
- description: Submission body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.SARIFSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: "#/definitions/types.SARIFSubmissionResponse"
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Submit a CRS generated SARIF
|
||||
tags:
|
||||
- submitted-sarif
|
||||
securityDefinitions:
|
||||
BasicAuth:
|
||||
type: basic
|
||||
swagger: "2.0"
|
||||
@@ -3,7 +3,7 @@
|
||||
"info": {
|
||||
"title": "Example Competition API",
|
||||
"contact": {},
|
||||
"version": "1.1.1"
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"paths": {
|
||||
"/v1/ping/": {
|
||||
@@ -27,6 +27,63 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/request/delta/": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BasicAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Send a delta task to the source of this request",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["request"],
|
||||
"summary": "Send a delta task to the source of this request",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Submission Body",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.RequestSubmission"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "No Content",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.Error"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.Error"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.Error"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/task/{task_id}/broadcast-sarif-assessment/{broadcast_sarif_id}/": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -800,7 +857,12 @@
|
||||
"format": "uuid"
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/definitions/types.SubmissionStatus"
|
||||
"description": "Schema-compliant submissions will only ever receive the statuses accepted or deadline_exceeded",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/types.SubmissionStatus"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -832,7 +894,12 @@
|
||||
"format": "uuid"
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/definitions/types.SubmissionStatus"
|
||||
"description": "Schema-compliant submissions will only ever receive the statuses accepted or deadline_exceeded",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/types.SubmissionStatus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"submitted_sarif_id": {
|
||||
"type": "string",
|
||||
@@ -864,7 +931,12 @@
|
||||
"format": "uuid"
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/definitions/types.SubmissionStatus"
|
||||
"description": "Schema-compliant submissions will only ever receive the statuses accepted or deadline_exceeded",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/types.SubmissionStatus"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -963,6 +1035,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.RequestSubmission": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"duration_secs": {
|
||||
"description": "Time in seconds until a task should expire. If not provided, defaults to 3600.",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.SARIFSubmission": {
|
||||
"type": "object",
|
||||
"required": ["sarif"],
|
||||
@@ -978,7 +1059,12 @@
|
||||
"required": ["status", "submitted_sarif_id"],
|
||||
"properties": {
|
||||
"status": {
|
||||
"$ref": "#/definitions/types.SubmissionStatus"
|
||||
"description": "Schema-compliant submissions will only ever receive the statuses accepted or deadline_exceeded",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/types.SubmissionStatus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"submitted_sarif_id": {
|
||||
"type": "string",
|
||||
|
||||
@@ -42,7 +42,11 @@ definitions:
|
||||
format: uuid
|
||||
type: string
|
||||
status:
|
||||
$ref: "#/definitions/types.SubmissionStatus"
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.SubmissionStatus"
|
||||
description:
|
||||
Schema-compliant submissions will only ever receive the statuses
|
||||
accepted or deadline_exceeded
|
||||
required:
|
||||
- bundle_id
|
||||
- status
|
||||
@@ -67,7 +71,11 @@ definitions:
|
||||
format: uuid
|
||||
type: string
|
||||
status:
|
||||
$ref: "#/definitions/types.SubmissionStatus"
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.SubmissionStatus"
|
||||
description:
|
||||
Schema-compliant submissions will only ever receive the statuses
|
||||
accepted or deadline_exceeded
|
||||
submitted_sarif_id:
|
||||
format: uuid
|
||||
type: string
|
||||
@@ -92,7 +100,11 @@ definitions:
|
||||
format: uuid
|
||||
type: string
|
||||
status:
|
||||
$ref: "#/definitions/types.SubmissionStatus"
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.SubmissionStatus"
|
||||
description:
|
||||
Schema-compliant submissions will only ever receive the statuses
|
||||
accepted or deadline_exceeded
|
||||
required:
|
||||
- freeform_id
|
||||
- status
|
||||
@@ -191,6 +203,14 @@ definitions:
|
||||
required:
|
||||
- status
|
||||
type: object
|
||||
types.RequestSubmission:
|
||||
properties:
|
||||
duration_secs:
|
||||
description:
|
||||
Time in seconds until a task should expire. If not provided,
|
||||
defaults to 3600.
|
||||
type: integer
|
||||
type: object
|
||||
types.SARIFSubmission:
|
||||
properties:
|
||||
sarif:
|
||||
@@ -202,7 +222,11 @@ definitions:
|
||||
types.SARIFSubmissionResponse:
|
||||
properties:
|
||||
status:
|
||||
$ref: "#/definitions/types.SubmissionStatus"
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.SubmissionStatus"
|
||||
description:
|
||||
Schema-compliant submissions will only ever receive the statuses
|
||||
accepted or deadline_exceeded
|
||||
submitted_sarif_id:
|
||||
format: uuid
|
||||
type: string
|
||||
@@ -257,7 +281,7 @@ definitions:
|
||||
info:
|
||||
contact: {}
|
||||
title: Example Competition API
|
||||
version: 1.1.1
|
||||
version: 1.2.0
|
||||
paths:
|
||||
/v1/ping/:
|
||||
get:
|
||||
@@ -274,6 +298,46 @@ paths:
|
||||
summary: Test authentication creds and network connectivity
|
||||
tags:
|
||||
- ping
|
||||
/v1/request/delta/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Send a delta task to the source of this request
|
||||
parameters:
|
||||
- description: Submission Body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.RequestSubmission"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: No Content
|
||||
schema:
|
||||
type: string
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: "#/definitions/types.Error"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Send a delta task to the source of this request
|
||||
tags:
|
||||
- request
|
||||
/v1/task/{task_id}/broadcast-sarif-assessment/{broadcast_sarif_id}/:
|
||||
post:
|
||||
consumes:
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "Example CRS API",
|
||||
"contact": {},
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"paths": {
|
||||
"/status/": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BasicAuth": []
|
||||
}
|
||||
],
|
||||
"description": "report the status of the CRS",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["status"],
|
||||
"summary": "CRS Status",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Status Obect",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.Status"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BasicAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Reset all stats in the status endpoint.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["status"],
|
||||
"summary": "Reset status stats",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "No Content",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/sarif/": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BasicAuth": []
|
||||
}
|
||||
],
|
||||
"description": "submit a sarif broadcast",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["sarif"],
|
||||
"summary": "Submit Sarif Broadcast",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Vulnerability Broadcast",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.SARIFBroadcast"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "No Content",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/task/": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BasicAuth": []
|
||||
}
|
||||
],
|
||||
"description": "submit a task for work",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["task"],
|
||||
"summary": "Submit Task",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Submission body",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.Task"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "No Content",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BasicAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Cancel all previously submitted tasks. This is meant for edge case recovery in case something goes wrong.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["task"],
|
||||
"summary": "Cancel Tasks",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "No Content",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/task/{task_id}/": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BasicAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Cancel a task by id. This is meant for edge case recovery in case something goes wrong.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["task"],
|
||||
"summary": "Cancel Task",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Task ID",
|
||||
"name": "task_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "No Content",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"types.SARIFBroadcast": {
|
||||
"type": "object",
|
||||
"required": ["broadcasts", "message_id", "message_time"],
|
||||
"properties": {
|
||||
"broadcasts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/types.SARIFBroadcastDetail"
|
||||
}
|
||||
},
|
||||
"message_id": {
|
||||
"description": "Unique ID for this message. The system will retry sending messages if it does not receive a 200 response code.\nUse this to determine if you have already processed a message.",
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"message_time": {
|
||||
"description": "UNIX millisecond timestamp for when the message was sent",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.SARIFBroadcastDetail": {
|
||||
"type": "object",
|
||||
"required": ["metadata", "sarif", "sarif_id", "task_id"],
|
||||
"properties": {
|
||||
"metadata": {
|
||||
"description": "String to string map containing data that should be attached to outputs like log messages and OpenTelemetry trace attributes for traceability",
|
||||
"type": "object"
|
||||
},
|
||||
"sarif": {
|
||||
"description": "SARIF Report compliant with provided schema",
|
||||
"type": "object"
|
||||
},
|
||||
"sarif_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"task_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.SourceDetail": {
|
||||
"type": "object",
|
||||
"required": ["sha256", "type", "url"],
|
||||
"properties": {
|
||||
"sha256": {
|
||||
"description": "Integrity hash of the gzipped tarball",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"$ref": "#/definitions/types.SourceType"
|
||||
},
|
||||
"url": {
|
||||
"description": "URL to fetch the source gzipped tarball",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.SourceType": {
|
||||
"type": "string",
|
||||
"enum": ["repo", "fuzz-tooling", "diff"],
|
||||
"x-enum-varnames": [
|
||||
"SourceTypeRepo",
|
||||
"SourceTypeFuzzTooling",
|
||||
"SourceTypeDiff"
|
||||
]
|
||||
},
|
||||
"types.Status": {
|
||||
"type": "object",
|
||||
"required": ["ready", "since", "state", "version"],
|
||||
"properties": {
|
||||
"details": {
|
||||
"description": "This is optional arbitrary content that may be logged in error cases, but is mainly for interactive troubleshooting.",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ready": {
|
||||
"description": "Boolean indicating if the CRS is prepared to work on tasks. Do not return true unless you have successfully tested connectivity to the Competition API via /v1/ping/",
|
||||
"type": "boolean"
|
||||
},
|
||||
"since": {
|
||||
"description": "Last time task and submission stats were reset. Unix timestamp at millisecond resolution.",
|
||||
"type": "integer"
|
||||
},
|
||||
"state": {
|
||||
"description": "State of the currently running tasks and submissions",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/types.StatusState"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"description": "Version string for verification and reproducibility.\n\n- git commit\n\n- SemVer\n\n- etc",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.StatusState": {
|
||||
"type": "object",
|
||||
"required": ["tasks"],
|
||||
"properties": {
|
||||
"tasks": {
|
||||
"$ref": "#/definitions/types.StatusTasksState"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.StatusTasksState": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"canceled",
|
||||
"errored",
|
||||
"failed",
|
||||
"pending",
|
||||
"processing",
|
||||
"succeeded",
|
||||
"waiting"
|
||||
],
|
||||
"properties": {
|
||||
"canceled": {
|
||||
"description": "Number of tasks that competition infrastructure has cancelled",
|
||||
"type": "integer"
|
||||
},
|
||||
"errored": {
|
||||
"description": "Number of tasks that the CRS encountered an unrecoverable issue for",
|
||||
"type": "integer"
|
||||
},
|
||||
"failed": {
|
||||
"description": "Number of submissions that the competition infrastructure marked failed",
|
||||
"type": "integer"
|
||||
},
|
||||
"pending": {
|
||||
"description": "Number of tasks that the CRS has not started work on",
|
||||
"type": "integer"
|
||||
},
|
||||
"processing": {
|
||||
"description": "Number of tasks that the CRS is currently processing",
|
||||
"type": "integer"
|
||||
},
|
||||
"succeeded": {
|
||||
"description": "Number of submissions that the competition infrastructure marked passed",
|
||||
"type": "integer"
|
||||
},
|
||||
"waiting": {
|
||||
"description": "Number of submissions that the competition infrastructure is currently testing",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.Task": {
|
||||
"type": "object",
|
||||
"required": ["message_id", "message_time", "tasks"],
|
||||
"properties": {
|
||||
"message_id": {
|
||||
"description": "Unique ID for this message. The system will retry sending messages if it does not receive a 200 response code.\nUse this to determine if you have already processed a message.",
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"message_time": {
|
||||
"description": "UNIX millisecond timestamp for when the message was sent",
|
||||
"type": "integer"
|
||||
},
|
||||
"tasks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/types.TaskDetail"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.TaskDetail": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"deadline",
|
||||
"focus",
|
||||
"harnesses_included",
|
||||
"metadata",
|
||||
"project_name",
|
||||
"source",
|
||||
"task_id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"deadline": {
|
||||
"description": "UNIX millisecond timestamp by which any submissions for this task must be in",
|
||||
"type": "integer"
|
||||
},
|
||||
"focus": {
|
||||
"description": "Because the challenge task may contain multiple repositories, the folder in the type repo source tarball containing the main project.\nIt is still set when there is only one repository.\n\nThis is the project the CRS is meant to submit vulns, patches, and SARIF assessments against.",
|
||||
"type": "string"
|
||||
},
|
||||
"harnesses_included": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"metadata": {
|
||||
"description": "String to string map containing data that should be attached to outputs like log messages and OpenTelemetry trace attributes for traceability",
|
||||
"type": "object"
|
||||
},
|
||||
"project_name": {
|
||||
"description": "OSS Fuzz project name",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"description": "List of sources needed to evaluate a task",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/types.SourceDetail"
|
||||
}
|
||||
},
|
||||
"task_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"type": {
|
||||
"$ref": "#/definitions/types.TaskType"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.TaskType": {
|
||||
"type": "string",
|
||||
"enum": ["full", "delta"],
|
||||
"x-enum-varnames": ["TaskTypeFull", "TaskTypeDelta"]
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"BasicAuth": {
|
||||
"type": "basic"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
definitions:
|
||||
types.SARIFBroadcast:
|
||||
properties:
|
||||
broadcasts:
|
||||
items:
|
||||
$ref: "#/definitions/types.SARIFBroadcastDetail"
|
||||
type: array
|
||||
message_id:
|
||||
description: |-
|
||||
Unique ID for this message. The system will retry sending messages if it does not receive a 200 response code.
|
||||
Use this to determine if you have already processed a message.
|
||||
format: uuid
|
||||
type: string
|
||||
message_time:
|
||||
description: UNIX millisecond timestamp for when the message was sent
|
||||
type: integer
|
||||
required:
|
||||
- broadcasts
|
||||
- message_id
|
||||
- message_time
|
||||
type: object
|
||||
types.SARIFBroadcastDetail:
|
||||
properties:
|
||||
metadata:
|
||||
description:
|
||||
String to string map containing data that should be attached
|
||||
to outputs like log messages and OpenTelemetry trace attributes for traceability
|
||||
type: object
|
||||
sarif:
|
||||
description: SARIF Report compliant with provided schema
|
||||
type: object
|
||||
sarif_id:
|
||||
format: uuid
|
||||
type: string
|
||||
task_id:
|
||||
format: uuid
|
||||
type: string
|
||||
required:
|
||||
- metadata
|
||||
- sarif
|
||||
- sarif_id
|
||||
- task_id
|
||||
type: object
|
||||
types.SourceDetail:
|
||||
properties:
|
||||
sha256:
|
||||
description: Integrity hash of the gzipped tarball
|
||||
type: string
|
||||
type:
|
||||
$ref: "#/definitions/types.SourceType"
|
||||
url:
|
||||
description: URL to fetch the source gzipped tarball
|
||||
type: string
|
||||
required:
|
||||
- sha256
|
||||
- type
|
||||
- url
|
||||
type: object
|
||||
types.SourceType:
|
||||
enum:
|
||||
- repo
|
||||
- fuzz-tooling
|
||||
- diff
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- SourceTypeRepo
|
||||
- SourceTypeFuzzTooling
|
||||
- SourceTypeDiff
|
||||
types.Status:
|
||||
properties:
|
||||
details:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description:
|
||||
This is optional arbitrary content that may be logged in error
|
||||
cases, but is mainly for interactive troubleshooting.
|
||||
type: object
|
||||
ready:
|
||||
description:
|
||||
Boolean indicating if the CRS is prepared to work on tasks. Do
|
||||
not return true unless you have successfully tested connectivity to the
|
||||
Competition API via /v1/ping/
|
||||
type: boolean
|
||||
since:
|
||||
description:
|
||||
Last time task and submission stats were reset. Unix timestamp
|
||||
at millisecond resolution.
|
||||
type: integer
|
||||
state:
|
||||
allOf:
|
||||
- $ref: "#/definitions/types.StatusState"
|
||||
description: State of the currently running tasks and submissions
|
||||
version:
|
||||
description: |-
|
||||
Version string for verification and reproducibility.
|
||||
|
||||
- git commit
|
||||
|
||||
- SemVer
|
||||
|
||||
- etc
|
||||
type: string
|
||||
required:
|
||||
- ready
|
||||
- since
|
||||
- state
|
||||
- version
|
||||
type: object
|
||||
types.StatusState:
|
||||
properties:
|
||||
tasks:
|
||||
$ref: "#/definitions/types.StatusTasksState"
|
||||
required:
|
||||
- tasks
|
||||
type: object
|
||||
types.StatusTasksState:
|
||||
properties:
|
||||
canceled:
|
||||
description: Number of tasks that competition infrastructure has cancelled
|
||||
type: integer
|
||||
errored:
|
||||
description:
|
||||
Number of tasks that the CRS encountered an unrecoverable issue
|
||||
for
|
||||
type: integer
|
||||
failed:
|
||||
description:
|
||||
Number of submissions that the competition infrastructure marked
|
||||
failed
|
||||
type: integer
|
||||
pending:
|
||||
description: Number of tasks that the CRS has not started work on
|
||||
type: integer
|
||||
processing:
|
||||
description: Number of tasks that the CRS is currently processing
|
||||
type: integer
|
||||
succeeded:
|
||||
description:
|
||||
Number of submissions that the competition infrastructure marked
|
||||
passed
|
||||
type: integer
|
||||
waiting:
|
||||
description:
|
||||
Number of submissions that the competition infrastructure is
|
||||
currently testing
|
||||
type: integer
|
||||
required:
|
||||
- canceled
|
||||
- errored
|
||||
- failed
|
||||
- pending
|
||||
- processing
|
||||
- succeeded
|
||||
- waiting
|
||||
type: object
|
||||
types.Task:
|
||||
properties:
|
||||
message_id:
|
||||
description: |-
|
||||
Unique ID for this message. The system will retry sending messages if it does not receive a 200 response code.
|
||||
Use this to determine if you have already processed a message.
|
||||
format: uuid
|
||||
type: string
|
||||
message_time:
|
||||
description: UNIX millisecond timestamp for when the message was sent
|
||||
type: integer
|
||||
tasks:
|
||||
items:
|
||||
$ref: "#/definitions/types.TaskDetail"
|
||||
type: array
|
||||
required:
|
||||
- message_id
|
||||
- message_time
|
||||
- tasks
|
||||
type: object
|
||||
types.TaskDetail:
|
||||
properties:
|
||||
deadline:
|
||||
description:
|
||||
UNIX millisecond timestamp by which any submissions for this
|
||||
task must be in
|
||||
type: integer
|
||||
focus:
|
||||
description: |-
|
||||
Because the challenge task may contain multiple repositories, the folder in the type repo source tarball containing the main project.
|
||||
It is still set when there is only one repository.
|
||||
|
||||
This is the project the CRS is meant to submit vulns, patches, and SARIF assessments against.
|
||||
type: string
|
||||
harnesses_included:
|
||||
type: boolean
|
||||
metadata:
|
||||
description:
|
||||
String to string map containing data that should be attached
|
||||
to outputs like log messages and OpenTelemetry trace attributes for traceability
|
||||
type: object
|
||||
project_name:
|
||||
description: OSS Fuzz project name
|
||||
type: string
|
||||
source:
|
||||
description: List of sources needed to evaluate a task
|
||||
items:
|
||||
$ref: "#/definitions/types.SourceDetail"
|
||||
type: array
|
||||
task_id:
|
||||
format: uuid
|
||||
type: string
|
||||
type:
|
||||
$ref: "#/definitions/types.TaskType"
|
||||
required:
|
||||
- deadline
|
||||
- focus
|
||||
- harnesses_included
|
||||
- metadata
|
||||
- project_name
|
||||
- source
|
||||
- task_id
|
||||
- type
|
||||
type: object
|
||||
types.TaskType:
|
||||
enum:
|
||||
- full
|
||||
- delta
|
||||
type: string
|
||||
x-enum-varnames:
|
||||
- TaskTypeFull
|
||||
- TaskTypeDelta
|
||||
info:
|
||||
contact: {}
|
||||
title: Example CRS API
|
||||
version: 1.2.0
|
||||
paths:
|
||||
/status/:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Reset all stats in the status endpoint.
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: No Content
|
||||
schema:
|
||||
type: string
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Reset status stats
|
||||
tags:
|
||||
- status
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: report the status of the CRS
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: Status Obect
|
||||
schema:
|
||||
$ref: "#/definitions/types.Status"
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: CRS Status
|
||||
tags:
|
||||
- status
|
||||
/v1/sarif/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: submit a sarif broadcast
|
||||
parameters:
|
||||
- description: Vulnerability Broadcast
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.SARIFBroadcast"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: No Content
|
||||
schema:
|
||||
type: string
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Submit Sarif Broadcast
|
||||
tags:
|
||||
- sarif
|
||||
/v1/task/:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description:
|
||||
Cancel all previously submitted tasks. This is meant for edge case
|
||||
recovery in case something goes wrong.
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: No Content
|
||||
schema:
|
||||
type: string
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Cancel Tasks
|
||||
tags:
|
||||
- task
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: submit a task for work
|
||||
parameters:
|
||||
- description: Submission body
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/types.Task"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"202":
|
||||
description: No Content
|
||||
schema:
|
||||
type: string
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Submit Task
|
||||
tags:
|
||||
- task
|
||||
/v1/task/{task_id}/:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description:
|
||||
Cancel a task by id. This is meant for edge case recovery in case
|
||||
something goes wrong.
|
||||
parameters:
|
||||
- description: Task ID
|
||||
format: uuid
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: No Content
|
||||
schema:
|
||||
type: string
|
||||
security:
|
||||
- BasicAuth: []
|
||||
summary: Cancel Task
|
||||
tags:
|
||||
- task
|
||||
securityDefinitions:
|
||||
BasicAuth:
|
||||
type: basic
|
||||
swagger: "2.0"
|
||||
@@ -3,7 +3,7 @@
|
||||
"info": {
|
||||
"title": "Example CRS API",
|
||||
"contact": {},
|
||||
"version": "1.1"
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"paths": {
|
||||
"/status/": {
|
||||
@@ -179,10 +179,12 @@
|
||||
}
|
||||
},
|
||||
"message_id": {
|
||||
"description": "Unique ID for this message. The system will retry sending messages if it does not receive a 200 response code.\nUse this to determine if you have already processed a message.",
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"message_time": {
|
||||
"description": "UNIX millisecond timestamp for when the message was sent",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
@@ -251,7 +253,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"since": {
|
||||
"description": "Last time task and submission stats were reset",
|
||||
"description": "Last time task and submission stats were reset. Unix timestamp at millisecond resolution.",
|
||||
"type": "integer"
|
||||
},
|
||||
"state": {
|
||||
@@ -324,10 +326,12 @@
|
||||
"required": ["message_id", "message_time", "tasks"],
|
||||
"properties": {
|
||||
"message_id": {
|
||||
"description": "Unique ID for this message. The system will retry sending messages if it does not receive a 200 response code.\nUse this to determine if you have already processed a message.",
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"message_time": {
|
||||
"description": "UNIX millisecond timestamp for when the message was sent",
|
||||
"type": "integer"
|
||||
},
|
||||
"tasks": {
|
||||
@@ -352,7 +356,7 @@
|
||||
],
|
||||
"properties": {
|
||||
"deadline": {
|
||||
"description": "UNIX timestamp by which any submissions for this task must be in",
|
||||
"description": "UNIX millisecond timestamp by which any submissions for this task must be in",
|
||||
"type": "integer"
|
||||
},
|
||||
"focus": {
|
||||
|
||||
@@ -6,9 +6,13 @@ definitions:
|
||||
$ref: "#/definitions/types.SARIFBroadcastDetail"
|
||||
type: array
|
||||
message_id:
|
||||
description: |-
|
||||
Unique ID for this message. The system will retry sending messages if it does not receive a 200 response code.
|
||||
Use this to determine if you have already processed a message.
|
||||
format: uuid
|
||||
type: string
|
||||
message_time:
|
||||
description: UNIX millisecond timestamp for when the message was sent
|
||||
type: integer
|
||||
required:
|
||||
- broadcasts
|
||||
@@ -78,7 +82,9 @@ definitions:
|
||||
Competition API via /v1/ping/
|
||||
type: boolean
|
||||
since:
|
||||
description: Last time task and submission stats were reset
|
||||
description:
|
||||
Last time task and submission stats were reset. Unix timestamp
|
||||
at millisecond resolution.
|
||||
type: integer
|
||||
state:
|
||||
allOf:
|
||||
@@ -150,9 +156,13 @@ definitions:
|
||||
types.Task:
|
||||
properties:
|
||||
message_id:
|
||||
description: |-
|
||||
Unique ID for this message. The system will retry sending messages if it does not receive a 200 response code.
|
||||
Use this to determine if you have already processed a message.
|
||||
format: uuid
|
||||
type: string
|
||||
message_time:
|
||||
description: UNIX millisecond timestamp for when the message was sent
|
||||
type: integer
|
||||
tasks:
|
||||
items:
|
||||
@@ -167,8 +177,8 @@ definitions:
|
||||
properties:
|
||||
deadline:
|
||||
description:
|
||||
UNIX timestamp by which any submissions for this task must be
|
||||
in
|
||||
UNIX millisecond timestamp by which any submissions for this
|
||||
task must be in
|
||||
type: integer
|
||||
focus:
|
||||
description: |-
|
||||
@@ -218,7 +228,7 @@ definitions:
|
||||
info:
|
||||
contact: {}
|
||||
title: Example CRS API
|
||||
version: "1.1"
|
||||
version: 1.2.0
|
||||
paths:
|
||||
/status/:
|
||||
delete:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "AIXCC Enhanced Static Analysis Results Format (SARIF) Version 2.1.0 JSON Schema",
|
||||
"id": "https://aixcc.tech/sarif-schema-v0.3.json",
|
||||
"description": "AIXCC Enhanced Static Analysis Results Format (SARIF) Version 2.1.0 JSON Schema: a standard format for the output of static analysis tools.",
|
||||
"title": "Static Analysis Results Format (SARIF) Version 2.1.0 JSON Schema",
|
||||
"id": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
|
||||
"description": "Static Analysis Results Format (SARIF) Version 2.1.0 JSON Schema: a standard format for the output of static analysis tools.",
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2233,7 +2233,7 @@
|
||||
"$ref": "#/definitions/propertyBag"
|
||||
}
|
||||
},
|
||||
"required": ["message", "ruleId"]
|
||||
"required": ["message"]
|
||||
},
|
||||
|
||||
"resultProvenance": {
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
# Tailnet-accessible hosted Competitor Test Server
|
||||
|
||||
The organizers have set up a test competition API server for each team that is reachable from the internet, but tasks your CRS hosted on the tailnet. Telemetry from these runs get forwarded to your team’s telemetry
|
||||
server.
|
||||
|
||||
It is intended that competitors may use this to task their CRS with challenges from prior rounds that are available in the aixcc-finals org. There are three changes to your CRS deployment that are required in order for
|
||||
you to use this server.
|
||||
|
||||
1. Change the URL of the Competition API to `https://test-<team-moniker>-api.tail7e9b4c.ts.net`
|
||||
2. If you are using Kubernetes Tailscale Operator, add another Service for this test URL so that it can be accessible from your cluster. See
|
||||
[proxies.yaml](https://github.com/aixcc-finals/example-crs-architecture/blob/main/example-crs-architecture/k8s/base/tailscale-connections/proxies.yaml) for context.
|
||||
3. Append `-testing` to your CRS hostname, for example `team-moniker-testing`. This is the URL that is configured by default.
|
||||
|
||||
If you want to use a different CRS URL **for the tailscale-hosted competitor test server**, use the following:
|
||||
|
||||
Update CRS hostname used by the hosted competitor testing server
|
||||
|
||||
```bash
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X PATCH https://<team-moniker>.tasker.aixcc.tech/crs/url/ -H 'Content-Type: application/json' -d '{"hostname":"team-moniker-testing-1"}'
|
||||
```
|
||||
|
||||
Get CRS hostname used by the hosted competitor testing server
|
||||
|
||||
```bash
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 https://<team-moniker>.tasker.aixcc.tech/crs/url/
|
||||
```
|
||||
|
||||
Kick off tasks with the server
|
||||
|
||||
```bash
|
||||
# Integration Test
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X 'POST' 'https://<team-moniker>.tasker.aixcc.tech/v1/request/delta/'
|
||||
# LibPNG
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X 'POST' 'https://<team-moniker>.tasker.aixcc.tech/webhook/trigger_task' -H 'Content-Type: application/json' -d '{
|
||||
"challenge_repo_url": "git@github.com:aixcc-finals/example-libpng.git",
|
||||
"challenge_repo_base_ref": "0cc367aaeaac3f888f255cee5d394968996f736e",
|
||||
"challenge_repo_head_ref": "fdacd5a1dcff42175117d674b0fda9f8a005ae88",
|
||||
"fuzz_tooling_url": "https://github.com/aixcc-finals/oss-fuzz-aixcc.git",
|
||||
"fuzz_tooling_ref": "d5fbd68fca66e6fa4f05899170d24e572b01853d",
|
||||
"fuzz_tooling_project_name": "libpng",
|
||||
"duration": 3600
|
||||
}'
|
||||
# Zookeeper
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X 'POST' 'https://<team-moniker>.tasker.aixcc.tech/webhook/trigger_task' -H 'Content-Type: application/json' -d '{
|
||||
"challenge_repo_url": "git@github.com:aixcc-finals/afc-zookeeper.git",
|
||||
"challenge_repo_base_ref": "d19cef9ca254a4c1461490ed8b82ffccfa57461d",
|
||||
"challenge_repo_head_ref": "5ee4f185d0431cc88f365ce779aa04a87fe7690f",
|
||||
"fuzz_tooling_url": "https://github.com/aixcc-finals/oss-fuzz-aixcc.git",
|
||||
"fuzz_tooling_ref": "challenge-state/zk-ex1-delta-01",
|
||||
"fuzz_tooling_project_name": "zookeeper",
|
||||
"duration": 3600
|
||||
}'
|
||||
# Libxml2
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X 'POST' 'https://<team-moniker>.tasker.aixcc.tech/webhook/trigger_task' -H 'Content-Type: application/json' -d '{
|
||||
"challenge_repo_url": "git@github.com:aixcc-finals/afc-libxml2.git",
|
||||
"challenge_repo_base_ref": "792cc4a1462d4a969d9d38bd80a52d2e4f7bd137",
|
||||
"challenge_repo_head_ref": "9d1cb67c31933ee5ae3ee458940f7dbeb2fde8b8",
|
||||
"fuzz_tooling_url": "https://github.com/aixcc-finals/oss-fuzz-aixcc.git",
|
||||
"fuzz_tooling_ref": "challenge-state/lx-ex1-delta-01",
|
||||
"fuzz_tooling_project_name": "libxml2",
|
||||
"duration": 3600
|
||||
}'
|
||||
|
||||
```
|
||||
|
||||
## IMPORTANT NOTE
|
||||
|
||||
If you are using this test server, don’t forget to change your Competition API URL back to `https://api.tail7e9b4c.ts.net` prior to the start of the round.
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Tailscale Management Tools
|
||||
|
||||
Each team has access to a set of APIs to manage their Tailscale devices. You can use this tool to list devices, delete devices, and update hostnames of tailscale devices. Each endpoint uses the Competition API
|
||||
credentials for your team.
|
||||
|
||||
List Devices
|
||||
|
||||
Lists devices on the tailnet for your team.
|
||||
|
||||
```bash
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 https://<team-moniker>.tasker.aixcc.tech/tailscale/device/
|
||||
```
|
||||
|
||||
Show Device
|
||||
|
||||
Shows information about a single device by name
|
||||
|
||||
```bash
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 https://<team-moniker>.tasker.aixcc.tech/tailscale/device/team-moniker-foo
|
||||
```
|
||||
|
||||
Rename Device
|
||||
|
||||
Change the hostname of a device on the tailnet
|
||||
|
||||
```bash
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X PATCH https://<team-moniker>.tasker.aixcc.tech/tailscale/device/team-moniker-foo -H 'Content-Type: application/json' -d '{"hostname":"team-moniker-exhibition2"}'
|
||||
```
|
||||
|
||||
Delete Device
|
||||
|
||||
Deletes a specific device on the tailnet
|
||||
|
||||
```bash
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X DELETE https://<team-moniker>.tasker.aixcc.tech/tailscale/device/team-moniker-foo
|
||||
```
|
||||
|
||||
Delete all Devices
|
||||
|
||||
**WARNING** This deletes all devices on your team’s tailnet.
|
||||
|
||||
```bash
|
||||
curl -u 11111111-1111-1111-1111-111111111111:pY8rLk7FvQ2hZm9GwUx3Ej5BnTcV4So0 -X DELETE https://<team-moniker>.tasker.aixcc.tech/tailscale/device/
|
||||
```
|
||||
@@ -1,5 +1,7 @@
|
||||
# CRS Telemetry Specification v1.0
|
||||
|
||||
For Telemetry Best Practices, see [here](telemetry_best_practices.md)
|
||||
|
||||
Telemetry generated by a CRS is submitted in two distinct ways:
|
||||
|
||||
1. GenAI (LLM requests and responses)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# General telemetry guidance
|
||||
|
||||
1. All work performed on challenges should be described by spans, and these spans must specify `round.id`, `task.id`, `crs.action.category` and `crs.action.name` (teams are free to choose their own names for
|
||||
crs.action.name, but it should be descriptive of the kind of work being performed)
|
||||
1. Spans/Traces should not be used for general-purpose logging. Use OpenTelemetry Logs for this purpose.
|
||||
1. All LLM requests' telemetry must be linked to a parent span that describes a unit of work that the LLM request contributes towards.
|
||||
|
||||
## Improving the structure of OTEL data
|
||||
|
||||
1. A trace is made up of spans that share a `trace_id` , and a trace must describe a distinct non-trivial effort that is mapped to a single `task.id`. Said differently: a trace should not span across multiple tasks, but
|
||||
a single task may have multiple traces.
|
||||
1. A trace may have one or more “root spans” (a span with no `parent_span_id`), but a single root span per trace is preferred.
|
||||
1. A trace should encompass a non-trivial number of spans. A small number of spans in a trace should indicate unusual or exceptional behavior.
|
||||
1. Spans must be linked to indicate relationships between spans either via parent/child relationships or via span links
|
||||
1. A parent/child relationship indicated by `parent_span_id` is expected for all units of work that are nested under a larger unit of work (e.g. function calls under an API endpoint, or LLM queries to service an
|
||||
asynchronous task).
|
||||
1. In cases where a multiple spans contribute to a new unit of work, or spans have a causal relationship (asynchronous, sequential, etc), span `links` must be used instead of parent/child relationships.
|
||||
1. In order for the telemetry data to be meaningful, the links between spans must reflect the order and hierarchy of work performed. This means that span relationships should generally form tree-like graphs rather
|
||||
than unlinked spans. Accomplishing this may require adding a telemetry span at a higher logical level in order to properly describe the hierarchy of work performed.
|
||||
|
||||
## Verifying telemetry
|
||||
|
||||
On your team's SigNoz server, you may check for the following attributes: `crs.action.category`, `round.id`, `task.id`, & `gen_ai.request.model` as a general means to verify the requested telemetry is being provided.
|
||||
|
||||
These attributes provide the following:
|
||||
|
||||
- `crs.action.category` attribute confirms CRS telemetry spans were sent
|
||||
- `round.id/task.id` are examples of attributes from a Task's `metadata` field. These need to be supplied in the spans. (confirms correct task metadata field passthrough)
|
||||
- `gen_ai.request.model` attribute existing confirms LLM telemetry
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "orchestrator"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
description = "Buttercup orchestrator"
|
||||
readme = "README.md"
|
||||
authors = [{ name = "Trail of Bits", email = "opensource@trailofbits.com" }]
|
||||
|
||||
@@ -1 +1 @@
|
||||
7.13.0-SNAPSHOT
|
||||
7.14.0-SNAPSHOT
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ class TypesArchitecture(str, Enum):
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
X86_64 = 'x86_64'
|
||||
ArchitectureX8664 = 'x86_64'
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ class TypesAssessment(str, Enum):
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
CORRECT = 'correct'
|
||||
INCORRECT = 'incorrect'
|
||||
AssessmentCorrect = 'correct'
|
||||
AssessmentIncorrect = 'incorrect'
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
|
||||
+5
-5
@@ -26,11 +26,11 @@ class TypesSubmissionStatus(str, Enum):
|
||||
"""
|
||||
allowed enum values
|
||||
"""
|
||||
ACCEPTED = 'accepted'
|
||||
PASSED = 'passed'
|
||||
FAILED = 'failed'
|
||||
DEADLINE_EXCEEDED = 'deadline_exceeded'
|
||||
ERRORED = 'errored'
|
||||
SubmissionStatusAccepted = 'accepted'
|
||||
SubmissionStatusPassed = 'passed'
|
||||
SubmissionStatusFailed = 'failed'
|
||||
SubmissionStatusDeadlineExceeded = 'deadline_exceeded'
|
||||
SubmissionStatusErrored = 'errored'
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Self:
|
||||
|
||||
@@ -14,12 +14,12 @@ from buttercup.common.datastructures.msg_pb2 import (
|
||||
Patch,
|
||||
)
|
||||
from buttercup.common.sarif_store import SARIFStore
|
||||
from buttercup.common.constants import ARCHITECTURE
|
||||
from buttercup.common.queues import QueueFactory, QueueNames
|
||||
from buttercup.common.telemetry import set_crs_attributes, CRSActionCategory
|
||||
|
||||
from buttercup.orchestrator.scheduler.sarif_matcher import match
|
||||
from buttercup.orchestrator.registry import TaskRegistry
|
||||
from buttercup.orchestrator.competition_api_client.models.types_architecture import TypesArchitecture
|
||||
from buttercup.orchestrator.competition_api_client.models.types_pov_submission import TypesPOVSubmission
|
||||
from buttercup.orchestrator.competition_api_client.models.types_patch_submission import TypesPatchSubmission
|
||||
from buttercup.orchestrator.competition_api_client.models.types_bundle_submission import TypesBundleSubmission
|
||||
@@ -142,7 +142,7 @@ class CompetitionAPI:
|
||||
|
||||
# Create submission payload from crash data
|
||||
submission = TypesPOVSubmission(
|
||||
architecture=ARCHITECTURE,
|
||||
architecture=TypesArchitecture.ArchitectureX8664,
|
||||
engine=crash.crash.target.engine,
|
||||
fuzzer_name=crash.crash.harness_name,
|
||||
sanitizer=crash.crash.target.sanitizer,
|
||||
@@ -168,7 +168,10 @@ class CompetitionAPI:
|
||||
payload=submission,
|
||||
)
|
||||
logger.debug(f"[{crash.crash.target.task_id}] POV submission response: {response}")
|
||||
if response.status not in [TypesSubmissionStatus.ACCEPTED, TypesSubmissionStatus.PASSED]:
|
||||
if response.status not in [
|
||||
TypesSubmissionStatus.SubmissionStatusAccepted,
|
||||
TypesSubmissionStatus.SubmissionStatusPassed,
|
||||
]:
|
||||
logger.error(
|
||||
f"[{crash.crash.target.task_id}] POV submission rejected (status: {response.status}) for harness: {crash.crash.harness_name}"
|
||||
)
|
||||
@@ -179,7 +182,7 @@ class CompetitionAPI:
|
||||
return response.pov_id, response.status
|
||||
except Exception as e:
|
||||
logger.error(f"[{crash.crash.target.task_id}] Failed to submit vulnerability: {e}")
|
||||
return None, TypesSubmissionStatus.ERRORED
|
||||
return None, TypesSubmissionStatus.SubmissionStatusErrored
|
||||
|
||||
def get_pov_status(self, task_id: str, pov_id: str) -> TypesSubmissionStatus:
|
||||
"""
|
||||
@@ -190,7 +193,7 @@ class CompetitionAPI:
|
||||
pov_id: POV ID from submit_vulnerability
|
||||
|
||||
Returns:
|
||||
TypesSubmissionStatus: Current status (ACCEPTED, PASSED, FAILED, ERRORED, DEADLINE_EXCEEDED)
|
||||
TypesSubmissionStatus: Current status (SubmissionStatusAccepted, SubmissionStatusPassed, SubmissionStatusFailed, SubmissionStatusErrored, SubmissionStatusDeadlineExceeded)
|
||||
"""
|
||||
assert task_id
|
||||
assert pov_id
|
||||
@@ -232,7 +235,10 @@ class CompetitionAPI:
|
||||
task_id=task_id, payload=submission
|
||||
)
|
||||
logger.debug(f"[{task_id}] Patch submission response: {response}")
|
||||
if response.status not in [TypesSubmissionStatus.ACCEPTED, TypesSubmissionStatus.PASSED]:
|
||||
if response.status not in [
|
||||
TypesSubmissionStatus.SubmissionStatusAccepted,
|
||||
TypesSubmissionStatus.SubmissionStatusPassed,
|
||||
]:
|
||||
logger.error(f"[{task_id}] Patch submission rejected (status: {response.status}) for harness: {patch}")
|
||||
span.set_status(Status(StatusCode.ERROR))
|
||||
return (None, response.status)
|
||||
@@ -249,7 +255,7 @@ class CompetitionAPI:
|
||||
patch_id: Patch ID from submit_patch
|
||||
|
||||
Returns:
|
||||
TypesSubmissionStatus: Current status (ACCEPTED, PASSED, FAILED, ERRORED, DEADLINE_EXCEEDED)
|
||||
TypesSubmissionStatus: Current status (SubmissionStatusAccepted, SubmissionStatusPassed, SubmissionStatusFailed, SubmissionStatusErrored, SubmissionStatusDeadlineExceeded)
|
||||
"""
|
||||
assert task_id
|
||||
assert patch_id
|
||||
@@ -300,7 +306,10 @@ class CompetitionAPI:
|
||||
task_id=task_id, payload=submission
|
||||
)
|
||||
logger.debug(f"[{task_id}] Bundle submission response: {response}")
|
||||
if response.status not in [TypesSubmissionStatus.ACCEPTED, TypesSubmissionStatus.PASSED]:
|
||||
if response.status not in [
|
||||
TypesSubmissionStatus.SubmissionStatusAccepted,
|
||||
TypesSubmissionStatus.SubmissionStatusPassed,
|
||||
]:
|
||||
logger.error(
|
||||
f"[{task_id}] Bundle submission rejected (status: {response.status}) for harness: {pov_id} {patch_id}"
|
||||
)
|
||||
@@ -344,7 +353,10 @@ class CompetitionAPI:
|
||||
task_id=task_id, bundle_id=bundle_id, payload=submission
|
||||
)
|
||||
logger.debug(f"[{task_id}] Bundle patch submission response: {response}")
|
||||
if response.status not in [TypesSubmissionStatus.ACCEPTED, TypesSubmissionStatus.PASSED]:
|
||||
if response.status not in [
|
||||
TypesSubmissionStatus.SubmissionStatusAccepted,
|
||||
TypesSubmissionStatus.SubmissionStatusPassed,
|
||||
]:
|
||||
logger.error(
|
||||
f"[{task_id}] Bundle patch submission rejected (status: {response.status}) for harness: {pov_id} {patch_id} {sarif_id}"
|
||||
)
|
||||
@@ -371,7 +383,7 @@ class CompetitionAPI:
|
||||
|
||||
# TODO: The description is the most basic I could think of. I don't know if we wanted to do something more fancy.
|
||||
submission = TypesSarifAssessmentSubmission(
|
||||
assessment=TypesAssessment.CORRECT,
|
||||
assessment=TypesAssessment.AssessmentCorrect,
|
||||
description="Overlapping with our POV/patch",
|
||||
)
|
||||
|
||||
@@ -391,7 +403,10 @@ class CompetitionAPI:
|
||||
task_id=task_id, broadcast_sarif_id=sarif_id, payload=submission
|
||||
)
|
||||
logger.debug(f"[{task_id}] Matching SARIF submission response: {response}")
|
||||
if response.status not in [TypesSubmissionStatus.ACCEPTED, TypesSubmissionStatus.PASSED]:
|
||||
if response.status not in [
|
||||
TypesSubmissionStatus.SubmissionStatusAccepted,
|
||||
TypesSubmissionStatus.SubmissionStatusPassed,
|
||||
]:
|
||||
logger.error(
|
||||
f"[{task_id}] Matching SARIF submission rejected (status: {response.status}) for sarif_id: {sarif_id}"
|
||||
)
|
||||
@@ -594,7 +609,7 @@ class Submissions:
|
||||
)
|
||||
|
||||
# If the API returned ERRORED, we want to retry.
|
||||
stop = status != TypesSubmissionStatus.ERRORED
|
||||
stop = status != TypesSubmissionStatus.SubmissionStatusErrored
|
||||
|
||||
if stop:
|
||||
logger.info(f"Competition API returned {status}, will not retry.")
|
||||
@@ -696,7 +711,7 @@ class Submissions:
|
||||
"""
|
||||
status = self.competition_api.get_pov_status(_task_id(e), e.pov_id)
|
||||
match status:
|
||||
case TypesSubmissionStatus.FAILED | TypesSubmissionStatus.DEADLINE_EXCEEDED:
|
||||
case TypesSubmissionStatus.SubmissionStatusFailed | TypesSubmissionStatus.SubmissionStatusDeadlineExceeded:
|
||||
e.state = SubmissionEntry.STOP
|
||||
self._persist(self.redis, i, e)
|
||||
log_structured(
|
||||
@@ -707,7 +722,7 @@ class Submissions:
|
||||
state_change=("WAIT_POV_PASS", "STOP"),
|
||||
msg=f"POV failed (status={status}), stopping",
|
||||
)
|
||||
case TypesSubmissionStatus.PASSED:
|
||||
case TypesSubmissionStatus.SubmissionStatusPassed:
|
||||
e.state = SubmissionEntry.SUBMIT_PATCH
|
||||
self._persist(self.redis, i, e)
|
||||
log_structured(
|
||||
@@ -718,7 +733,7 @@ class Submissions:
|
||||
state_change=("WAIT_POV_PASS", "SUBMIT_PATCH"),
|
||||
msg="POV passed, ready to submit patch when the patch is ready",
|
||||
)
|
||||
case TypesSubmissionStatus.ERRORED:
|
||||
case TypesSubmissionStatus.SubmissionStatusErrored:
|
||||
log_structured(logger.info, _task_id(e), index=i, pov_id=e.pov_id, msg="POV errored, will resubmit")
|
||||
|
||||
pov_id, status = self.competition_api.submit_pov(e.crash)
|
||||
@@ -730,7 +745,7 @@ class Submissions:
|
||||
)
|
||||
|
||||
# If the API returned ERRORED, we want to retry.
|
||||
if status != TypesSubmissionStatus.ERRORED:
|
||||
if status != TypesSubmissionStatus.SubmissionStatusErrored:
|
||||
e.state = SubmissionEntry.STOP
|
||||
self._persist(self.redis, i, e)
|
||||
log_structured(
|
||||
@@ -749,7 +764,7 @@ class Submissions:
|
||||
)
|
||||
|
||||
case _:
|
||||
assert status == TypesSubmissionStatus.ACCEPTED, f"Unexpected POV status: {status}"
|
||||
assert status == TypesSubmissionStatus.SubmissionStatusAccepted, f"Unexpected POV status: {status}"
|
||||
|
||||
def _submit_patch(self, i, e):
|
||||
"""
|
||||
@@ -794,7 +809,10 @@ class Submissions:
|
||||
)
|
||||
else:
|
||||
match status:
|
||||
case TypesSubmissionStatus.FAILED | TypesSubmissionStatus.DEADLINE_EXCEEDED:
|
||||
case (
|
||||
TypesSubmissionStatus.SubmissionStatusFailed
|
||||
| TypesSubmissionStatus.SubmissionStatusDeadlineExceeded
|
||||
):
|
||||
# Deadline exceeded or failed, move on to next patch (for exceeded we won't try again due to deadline check)
|
||||
e.patch_idx += 1
|
||||
self._persist(self.redis, i, e)
|
||||
@@ -806,7 +824,7 @@ class Submissions:
|
||||
patch_idx=e.patch_idx,
|
||||
msg=f"Patch submission failed ({status}), will not attempt this patch again.",
|
||||
)
|
||||
case TypesSubmissionStatus.ERRORED:
|
||||
case TypesSubmissionStatus.SubmissionStatusErrored:
|
||||
if have_more_patches and e.patch_submission_attempt >= self.patch_submission_retry_limit:
|
||||
_advance_patch_idx(e)
|
||||
self._persist(self.redis, i, e)
|
||||
@@ -847,9 +865,9 @@ class Submissions:
|
||||
"""
|
||||
status = self.competition_api.get_patch_status(_task_id(e), e.patch_id)
|
||||
match status:
|
||||
case TypesSubmissionStatus.ACCEPTED:
|
||||
case TypesSubmissionStatus.SubmissionStatusAccepted:
|
||||
return # No change.
|
||||
case TypesSubmissionStatus.FAILED | TypesSubmissionStatus.DEADLINE_EXCEEDED:
|
||||
case TypesSubmissionStatus.SubmissionStatusFailed | TypesSubmissionStatus.SubmissionStatusDeadlineExceeded:
|
||||
_advance_patch_idx(e)
|
||||
e.state = SubmissionEntry.SUBMIT_PATCH
|
||||
self._persist(self.redis, i, e)
|
||||
@@ -862,7 +880,7 @@ class Submissions:
|
||||
state_change=("WAIT_PATCH_PASS", "SUBMIT_PATCH"),
|
||||
msg=f"Patch submission failed ({status}), will not attempt this patch again, moving on to next patch.",
|
||||
)
|
||||
case TypesSubmissionStatus.ERRORED:
|
||||
case TypesSubmissionStatus.SubmissionStatusErrored:
|
||||
e.state = SubmissionEntry.SUBMIT_PATCH
|
||||
self._persist(self.redis, i, e)
|
||||
log_structured(
|
||||
@@ -874,7 +892,7 @@ class Submissions:
|
||||
state_change=("WAIT_PATCH_PASS", "SUBMIT_PATCH"),
|
||||
msg=f"Patch submission errored ({status}), will attempt this patch again.",
|
||||
)
|
||||
case TypesSubmissionStatus.PASSED:
|
||||
case TypesSubmissionStatus.SubmissionStatusPassed:
|
||||
e.state = SubmissionEntry.SUBMIT_BUNDLE
|
||||
self._persist(self.redis, i, e)
|
||||
log_structured(
|
||||
@@ -904,7 +922,10 @@ class Submissions:
|
||||
bundle_id, status = self.competition_api.submit_bundle(_task_id(e), e.pov_id, e.patch_id)
|
||||
if not bundle_id:
|
||||
match status:
|
||||
case TypesSubmissionStatus.FAILED | TypesSubmissionStatus.DEADLINE_EXCEEDED:
|
||||
case (
|
||||
TypesSubmissionStatus.SubmissionStatusFailed
|
||||
| TypesSubmissionStatus.SubmissionStatusDeadlineExceeded
|
||||
):
|
||||
e.state = SubmissionEntry.STOP
|
||||
self._persist(self.redis, i, e)
|
||||
log_structured(
|
||||
@@ -916,7 +937,7 @@ class Submissions:
|
||||
state_change=("SUBMIT_BUNDLE", "STOP"),
|
||||
msg=f"Bundle submission failed ({status}), not much else to do but stop.",
|
||||
)
|
||||
case TypesSubmissionStatus.ERRORED:
|
||||
case TypesSubmissionStatus.SubmissionStatusErrored:
|
||||
log_structured(
|
||||
logger.info,
|
||||
_task_id(e),
|
||||
@@ -1002,7 +1023,10 @@ class Submissions:
|
||||
)
|
||||
else:
|
||||
match status:
|
||||
case TypesSubmissionStatus.FAILED | TypesSubmissionStatus.DEADLINE_EXCEEDED:
|
||||
case (
|
||||
TypesSubmissionStatus.SubmissionStatusFailed
|
||||
| TypesSubmissionStatus.SubmissionStatusDeadlineExceeded
|
||||
):
|
||||
e.state = SubmissionEntry.STOP
|
||||
self._persist(self.redis, i, e)
|
||||
log_structured(
|
||||
@@ -1056,7 +1080,10 @@ class Submissions:
|
||||
)
|
||||
else:
|
||||
match status:
|
||||
case TypesSubmissionStatus.FAILED | TypesSubmissionStatus.DEADLINE_EXCEEDED:
|
||||
case (
|
||||
TypesSubmissionStatus.SubmissionStatusFailed
|
||||
| TypesSubmissionStatus.SubmissionStatusDeadlineExceeded
|
||||
):
|
||||
e.state = SubmissionEntry.STOP
|
||||
self._persist(self.redis, i, e)
|
||||
log_structured(
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# generated by fastapi-codegen:
|
||||
# filename: /tmp/tmp.4yUHNSUOxp/openapi.json
|
||||
# timestamp: 2025-03-19T10:11:57+00:00
|
||||
# filename: /tmp/tmp.0oVFmuzKjt/openapi.json
|
||||
# timestamp: 2025-05-02T05:12:50+00:00
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# generated by fastapi-codegen:
|
||||
# filename: /tmp/tmp.4yUHNSUOxp/openapi.json
|
||||
# timestamp: 2025-03-19T10:11:57+00:00
|
||||
# filename: /tmp/tmp.0oVFmuzKjt/openapi.json
|
||||
# timestamp: 2025-05-02T05:12:50+00:00
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# generated by fastapi-codegen:
|
||||
# filename: openapi.json
|
||||
# timestamp: 2025-02-18T14:23:33+00:00
|
||||
# timestamp: 2025-05-02T05:12:50+00:00
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ def mock_redis():
|
||||
def mock_competition_api(mock_task_registry):
|
||||
mock = Mock(spec=CompetitionAPI)
|
||||
# Add the missing method that's needed in tests
|
||||
mock.submit_bundle_patch = Mock(return_value=(True, TypesSubmissionStatus.ACCEPTED))
|
||||
mock.submit_bundle_patch = Mock(return_value=(True, TypesSubmissionStatus.SubmissionStatusAccepted))
|
||||
return mock
|
||||
|
||||
|
||||
@@ -122,7 +122,9 @@ class TestCompetitionAPI:
|
||||
mock_lopen.return_value.__enter__.return_value = mock_file
|
||||
|
||||
# Setup API response
|
||||
mock_response = TypesPOVSubmissionResponse(status=TypesSubmissionStatus.ACCEPTED, pov_id="test-pov-123")
|
||||
mock_response = TypesPOVSubmissionResponse(
|
||||
status=TypesSubmissionStatus.SubmissionStatusAccepted, pov_id="test-pov-123"
|
||||
)
|
||||
|
||||
# Setup API client mock
|
||||
mock_pov_api = Mock()
|
||||
@@ -135,7 +137,7 @@ class TestCompetitionAPI:
|
||||
|
||||
# Verify result first
|
||||
assert result[0] == "test-pov-123"
|
||||
assert result[1] == TypesSubmissionStatus.ACCEPTED
|
||||
assert result[1] == TypesSubmissionStatus.SubmissionStatusAccepted
|
||||
|
||||
# Verify file was read correctly
|
||||
mock_lopen.assert_called_once_with(sample_crash.crash.crash_input_path, "rb")
|
||||
@@ -160,7 +162,7 @@ class TestCompetitionAPI:
|
||||
mock_lopen.return_value.__enter__.return_value = mock_file
|
||||
|
||||
# Setup API response
|
||||
mock_response = TypesPOVSubmissionResponse(status=TypesSubmissionStatus.FAILED, pov_id="")
|
||||
mock_response = TypesPOVSubmissionResponse(status=TypesSubmissionStatus.SubmissionStatusFailed, pov_id="")
|
||||
|
||||
# Setup API client mock
|
||||
mock_pov_api = Mock()
|
||||
@@ -173,12 +175,14 @@ class TestCompetitionAPI:
|
||||
|
||||
# Verify result is a tuple with (None, FAILED)
|
||||
assert result[0] is None
|
||||
assert result[1] == TypesSubmissionStatus.FAILED
|
||||
assert result[1] == TypesSubmissionStatus.SubmissionStatusFailed
|
||||
|
||||
def test_get_pov_status(self, competition_api):
|
||||
# Setup mock
|
||||
mock_pov_api = Mock()
|
||||
mock_pov_api.v1_task_task_id_pov_pov_id_get.return_value = Mock(status=TypesSubmissionStatus.PASSED)
|
||||
mock_pov_api.v1_task_task_id_pov_pov_id_get.return_value = Mock(
|
||||
status=TypesSubmissionStatus.SubmissionStatusPassed
|
||||
)
|
||||
|
||||
# Patch the PovApi constructor
|
||||
with patch("buttercup.orchestrator.scheduler.submissions.PovApi", return_value=mock_pov_api):
|
||||
@@ -187,7 +191,7 @@ class TestCompetitionAPI:
|
||||
|
||||
# Verify call and result
|
||||
mock_pov_api.v1_task_task_id_pov_pov_id_get.assert_called_once_with(task_id="task-123", pov_id="pov-456")
|
||||
assert status == TypesSubmissionStatus.PASSED
|
||||
assert status == TypesSubmissionStatus.SubmissionStatusPassed
|
||||
|
||||
def test_submit_patch_successful(self, competition_api):
|
||||
# Setup test data
|
||||
@@ -196,7 +200,9 @@ class TestCompetitionAPI:
|
||||
expected_encoded_patch = base64.b64encode(patch_content.encode()).decode()
|
||||
|
||||
# Setup mock response
|
||||
mock_response = TypesPatchSubmissionResponse(status=TypesSubmissionStatus.ACCEPTED, patch_id="patch-123")
|
||||
mock_response = TypesPatchSubmissionResponse(
|
||||
status=TypesSubmissionStatus.SubmissionStatusAccepted, patch_id="patch-123"
|
||||
)
|
||||
|
||||
# Setup patch API mock
|
||||
mock_patch_api = Mock()
|
||||
@@ -215,12 +221,14 @@ class TestCompetitionAPI:
|
||||
|
||||
# Verify result
|
||||
assert result[0] == "patch-123"
|
||||
assert result[1] == TypesSubmissionStatus.ACCEPTED
|
||||
assert result[1] == TypesSubmissionStatus.SubmissionStatusAccepted
|
||||
|
||||
def test_get_patch_status(self, competition_api):
|
||||
# Setup mock
|
||||
mock_patch_api = Mock()
|
||||
mock_patch_api.v1_task_task_id_patch_patch_id_get.return_value = Mock(status=TypesSubmissionStatus.PASSED)
|
||||
mock_patch_api.v1_task_task_id_patch_patch_id_get.return_value = Mock(
|
||||
status=TypesSubmissionStatus.SubmissionStatusPassed
|
||||
)
|
||||
|
||||
# Patch the PatchApi constructor
|
||||
with patch("buttercup.orchestrator.scheduler.submissions.PatchApi", return_value=mock_patch_api):
|
||||
@@ -231,7 +239,7 @@ class TestCompetitionAPI:
|
||||
mock_patch_api.v1_task_task_id_patch_patch_id_get.assert_called_once_with(
|
||||
task_id="task-123", patch_id="patch-456"
|
||||
)
|
||||
assert status == TypesSubmissionStatus.PASSED
|
||||
assert status == TypesSubmissionStatus.SubmissionStatusPassed
|
||||
|
||||
def test_submit_bundle_successful(self, competition_api):
|
||||
# Setup test data
|
||||
@@ -240,7 +248,9 @@ class TestCompetitionAPI:
|
||||
patch_id = "patch-789"
|
||||
|
||||
# Setup mock response
|
||||
mock_response = TypesBundleSubmissionResponse(status=TypesSubmissionStatus.ACCEPTED, bundle_id="bundle-123")
|
||||
mock_response = TypesBundleSubmissionResponse(
|
||||
status=TypesSubmissionStatus.SubmissionStatusAccepted, bundle_id="bundle-123"
|
||||
)
|
||||
|
||||
# Setup bundle API mock
|
||||
mock_bundle_api = Mock()
|
||||
@@ -260,7 +270,7 @@ class TestCompetitionAPI:
|
||||
|
||||
# Verify result
|
||||
assert result[0] == "bundle-123"
|
||||
assert result[1] == TypesSubmissionStatus.ACCEPTED
|
||||
assert result[1] == TypesSubmissionStatus.SubmissionStatusAccepted
|
||||
|
||||
def test_submit_matching_sarif_successful(self, competition_api):
|
||||
# Setup test data
|
||||
@@ -268,7 +278,7 @@ class TestCompetitionAPI:
|
||||
sarif_id = "sarif-456"
|
||||
|
||||
# Setup mock response
|
||||
mock_response = Mock(status=TypesSubmissionStatus.ACCEPTED)
|
||||
mock_response = Mock(status=TypesSubmissionStatus.SubmissionStatusAccepted)
|
||||
|
||||
# Setup sarif API mock
|
||||
mock_sarif_api = Mock()
|
||||
@@ -286,14 +296,14 @@ class TestCompetitionAPI:
|
||||
|
||||
# Verify result
|
||||
assert result[0] is True
|
||||
assert result[1] == TypesSubmissionStatus.ACCEPTED
|
||||
assert result[1] == TypesSubmissionStatus.SubmissionStatusAccepted
|
||||
|
||||
|
||||
# Tests for the Submissions class
|
||||
class TestSubmissions:
|
||||
def test_submit_vulnerability_successful(self, submissions, mock_competition_api, sample_crash, mock_redis):
|
||||
# Setup mock return value for submit_vulnerability
|
||||
mock_competition_api.submit_pov.return_value = ("test-pov-123", TypesSubmissionStatus.ACCEPTED)
|
||||
mock_competition_api.submit_pov.return_value = ("test-pov-123", TypesSubmissionStatus.SubmissionStatusAccepted)
|
||||
mock_redis.rpush.return_value = 1 # Index of the inserted entry
|
||||
|
||||
# Call the method
|
||||
@@ -315,7 +325,7 @@ class TestSubmissions:
|
||||
|
||||
def test_submit_vulnerability_failed(self, submissions, mock_competition_api, sample_crash):
|
||||
# Setup mock to return an error
|
||||
mock_competition_api.submit_pov.return_value = (None, TypesSubmissionStatus.FAILED)
|
||||
mock_competition_api.submit_pov.return_value = (None, TypesSubmissionStatus.SubmissionStatusFailed)
|
||||
|
||||
# Call the method
|
||||
result = submissions.submit_vulnerability(sample_crash)
|
||||
@@ -331,7 +341,7 @@ class TestSubmissions:
|
||||
|
||||
def test_submit_vulnerability_errored(self, submissions, mock_competition_api, sample_crash):
|
||||
# Setup mock to return an error
|
||||
mock_competition_api.submit_pov.return_value = (None, TypesSubmissionStatus.ERRORED)
|
||||
mock_competition_api.submit_pov.return_value = (None, TypesSubmissionStatus.SubmissionStatusErrored)
|
||||
|
||||
# Call the method
|
||||
result = submissions.submit_vulnerability(sample_crash)
|
||||
@@ -396,7 +406,7 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return PASSED
|
||||
mock_competition_api.get_pov_status.return_value = TypesSubmissionStatus.PASSED
|
||||
mock_competition_api.get_pov_status.return_value = TypesSubmissionStatus.SubmissionStatusPassed
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
@@ -410,7 +420,7 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return FAILED
|
||||
mock_competition_api.get_pov_status.return_value = TypesSubmissionStatus.FAILED
|
||||
mock_competition_api.get_pov_status.return_value = TypesSubmissionStatus.SubmissionStatusFailed
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
@@ -424,8 +434,8 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return ERRORED then successful resubmission
|
||||
mock_competition_api.get_pov_status.return_value = TypesSubmissionStatus.ERRORED
|
||||
mock_competition_api.submit_pov.return_value = ("new-pov-456", TypesSubmissionStatus.ACCEPTED)
|
||||
mock_competition_api.get_pov_status.return_value = TypesSubmissionStatus.SubmissionStatusErrored
|
||||
mock_competition_api.submit_pov.return_value = ("new-pov-456", TypesSubmissionStatus.SubmissionStatusAccepted)
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
@@ -445,7 +455,10 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return successful patch submission
|
||||
mock_competition_api.submit_patch.return_value = ("test-patch-123", TypesSubmissionStatus.ACCEPTED)
|
||||
mock_competition_api.submit_patch.return_value = (
|
||||
"test-patch-123",
|
||||
TypesSubmissionStatus.SubmissionStatusAccepted,
|
||||
)
|
||||
|
||||
# Mock the _have_more_patches function to avoid AttributeError
|
||||
with patch("buttercup.orchestrator.scheduler.submissions._have_more_patches", return_value=True):
|
||||
@@ -464,7 +477,7 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return PASSED
|
||||
mock_competition_api.get_patch_status.return_value = TypesSubmissionStatus.PASSED
|
||||
mock_competition_api.get_patch_status.return_value = TypesSubmissionStatus.SubmissionStatusPassed
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
@@ -484,7 +497,7 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return FAILED
|
||||
mock_competition_api.get_patch_status.return_value = TypesSubmissionStatus.FAILED
|
||||
mock_competition_api.get_patch_status.return_value = TypesSubmissionStatus.SubmissionStatusFailed
|
||||
|
||||
# Mock the _advance_patch_idx function to avoid AttributeError
|
||||
with patch("buttercup.orchestrator.scheduler.submissions._advance_patch_idx") as mock_advance:
|
||||
@@ -505,7 +518,10 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return successful bundle submission
|
||||
mock_competition_api.submit_bundle.return_value = ("test-bundle-789", TypesSubmissionStatus.ACCEPTED)
|
||||
mock_competition_api.submit_bundle.return_value = (
|
||||
"test-bundle-789",
|
||||
TypesSubmissionStatus.SubmissionStatusAccepted,
|
||||
)
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
@@ -522,7 +538,7 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return failed bundle submission
|
||||
mock_competition_api.submit_bundle.return_value = (None, TypesSubmissionStatus.FAILED)
|
||||
mock_competition_api.submit_bundle.return_value = (None, TypesSubmissionStatus.SubmissionStatusFailed)
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
@@ -538,7 +554,7 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return error
|
||||
mock_competition_api.submit_bundle.return_value = (None, TypesSubmissionStatus.ERRORED)
|
||||
mock_competition_api.submit_bundle.return_value = (None, TypesSubmissionStatus.SubmissionStatusErrored)
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
@@ -581,7 +597,7 @@ class TestStateTransitions:
|
||||
submissions.entries = [sample_submission_entry]
|
||||
|
||||
# Mock competition API to return successful bundle patch
|
||||
mock_competition_api.patch_bundle.return_value = (True, TypesSubmissionStatus.ACCEPTED)
|
||||
mock_competition_api.patch_bundle.return_value = (True, TypesSubmissionStatus.SubmissionStatusAccepted)
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
@@ -665,7 +681,10 @@ class TestStateTransitions:
|
||||
# Mock the _task_id function to verify it's being called with the right arguments
|
||||
with patch("buttercup.orchestrator.scheduler.submissions._task_id", return_value=task_id) as mock_task_id:
|
||||
# Mock competition API to return successful patch submission
|
||||
mock_competition_api.submit_patch.return_value = ("test-patch-123", TypesSubmissionStatus.ACCEPTED)
|
||||
mock_competition_api.submit_patch.return_value = (
|
||||
"test-patch-123",
|
||||
TypesSubmissionStatus.SubmissionStatusAccepted,
|
||||
)
|
||||
|
||||
# Simulate process_cycle
|
||||
submissions.process_cycle()
|
||||
|
||||
Reference in New Issue
Block a user