From c6bd7b2ec2fda4e53aaa1a1ee5401355384e8b5f Mon Sep 17 00:00:00 2001 From: He Weiwei Date: Wed, 19 May 2021 10:36:09 +0800 Subject: [PATCH] ci: lint the swagger file (#14916) Signed-off-by: He Weiwei --- .dockerignore | 2 + .spectral.yaml | 41 ++++++++++++ Makefile | 42 ++++++++---- api/v2.0/swagger.yaml | 67 +++++++++++++++++-- .../left-side-nav/gc-page/gc/gc.component.ts | 52 ++++++++------ .../replication-tasks.component.ts | 9 ++- ...lication-tasks-routing-resolver.service.ts | 5 +- .../create-edit-label.component.ts | 5 +- .../components/label/label.component.ts | 2 +- tools/spectral/Dockerfile | 8 +++ tools/spectral/functions/requireRequestId.js | 13 ++++ 11 files changed, 197 insertions(+), 49 deletions(-) create mode 100644 .spectral.yaml create mode 100644 tools/spectral/Dockerfile create mode 100644 tools/spectral/functions/requireRequestId.js diff --git a/.dockerignore b/.dockerignore index a94a8670c..507c8ecb6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,5 @@ src/portal/node_modules/ doc/ docs/ .git +make/common/config/ +harbor-offline-installer-*.tgz diff --git a/.spectral.yaml b/.spectral.yaml new file mode 100644 index 000000000..46bc1195b --- /dev/null +++ b/.spectral.yaml @@ -0,0 +1,41 @@ +extends: [[spectral:oas, all]] + +functionsDir: "./tools/spectral/functions" + +functions: [requireRequestId] + +rules: + info-contact: false + info-license: false + license-url: false + no-$ref-siblings: false + oas2-valid-definition-example: false + oas2-valid-response-schema-example: false + openapi-tags: false + operation-default-response: false + operation-tag-defined: false + + required-operationId: + description: must have a operationId. + given: $.paths[*][*] + severity: error + then: + field: operationId + function: truthy + + camel-case-operationId: + description: should be camelCased. + type: style + given: $.paths[*][*].operationId + then: + function: casing + functionOptions: + type: camel + + requestId-required: + description: must have a requestId paramaters. + given: $.paths[*][*] + severity: error + then: + field: parameters + function: requireRequestId diff --git a/Makefile b/Makefile index da51065fe..5e92d8633 100644 --- a/Makefile +++ b/Makefile @@ -295,17 +295,34 @@ ifeq ($(CHARTFLAG), true) DOCKERSAVE_PARA+= $(DOCKERIMAGENAME_CHART_SERVER):$(VERSIONTAG) endif + +RUNCONTAINER=$(DOCKERCMD) run --rm -u $(shell id -u):$(shell id -g) -v $(BUILDPATH):$(BUILDPATH) -w $(BUILDPATH) + +# $1 the name of the docker image +# $2 the tag of the docker image +# $3 the command to build the docker image +define prepare_docker_image + @if [ "$(shell ${DOCKERIMAGES} -q $(1):$(2) 2> /dev/null)" == "" ]; then \ + $(3) && echo "build $(1):$(2) successfully" || (echo "build $(1):$(2) failed" && exit 1) ; \ + fi +endef + +# lint swagger doc +SPECTRAL_IMAGENAME=goharbor/spectral +SPECTRAL_VERSION=v5.9.1 +SPECTRAL_IMAGE_BUILD_CMD=${DOCKERBUILD} -f ${TOOLSPATH}/spectral/Dockerfile --build-arg GOLANG=${GOBUILDIMAGE} --build-arg SPECTRAL_VERSION=${SPECTRAL_VERSION} -t ${SPECTRAL_IMAGENAME}:$(SPECTRAL_VERSION) . +SPECTRAL=$(RUNCONTAINER) $(SPECTRAL_IMAGENAME):$(SPECTRAL_VERSION) + +lint_apis: + $(call prepare_docker_image,${SPECTRAL_IMAGENAME},${SPECTRAL_VERSION},${SPECTRAL_IMAGE_BUILD_CMD}) + $(SPECTRAL) lint ./api/v2.0/swagger.yaml + SWAGGER_IMAGENAME=goharbor/swagger SWAGGER_VERSION=v0.25.0 -SWAGGER=$(DOCKERCMD) run --rm -u $(shell id -u):$(shell id -g) -v $(BUILDPATH):$(BUILDPATH) -w $(BUILDPATH) ${SWAGGER_IMAGENAME}:${SWAGGER_VERSION} +SWAGGER=$(RUNCONTAINER) ${SWAGGER_IMAGENAME}:${SWAGGER_VERSION} SWAGGER_GENERATE_SERVER=${SWAGGER} generate server --template-dir=$(TOOLSPATH)/swagger/templates --exclude-main --additional-initialism=CVE --additional-initialism=GC --additional-initialism=OIDC SWAGGER_IMAGE_BUILD_CMD=${DOCKERBUILD} -f ${TOOLSPATH}/swagger/Dockerfile --build-arg GOLANG=${GOBUILDIMAGE} --build-arg SWAGGER_VERSION=${SWAGGER_VERSION} -t ${SWAGGER_IMAGENAME}:$(SWAGGER_VERSION) . -SWAGGER_IMAGENAME: - @if [ "$(shell ${DOCKERIMAGES} -q ${SWAGGER_IMAGENAME}:$(SWAGGER_VERSION) 2> /dev/null)" == "" ]; then \ - ${SWAGGER_IMAGE_BUILD_CMD} && echo "build swagger image successfully" || (echo "build swagger image failed" && exit 1) ; \ - fi - # $1 the path of swagger spec # $2 the path of base directory for generating the files # $3 the name of the application @@ -316,21 +333,18 @@ define swagger_generate_server @$(SWAGGER_GENERATE_SERVER) -f $(1) -A $(3) --target $(2) endef -gen_apis: SWAGGER_IMAGENAME +gen_apis: lint_apis + $(call prepare_docker_image,${SWAGGER_IMAGENAME},${SWAGGER_VERSION},${SWAGGER_IMAGE_BUILD_CMD}) $(call swagger_generate_server,api/v2.0/swagger.yaml,src/server/v2.0,harbor) MOCKERY_IMAGENAME=goharbor/mockery MOCKERY_VERSION=v2.1.0 -MOCKERY=$(DOCKERCMD) run --rm -u $(shell id -u):$(shell id -g) -v $(BUILDPATH):$(BUILDPATH) -w $(BUILDPATH) ${MOCKERY_IMAGENAME}:${MOCKERY_VERSION} +MOCKERY=$(RUNCONTAINER) ${MOCKERY_IMAGENAME}:${MOCKERY_VERSION} MOCKERY_IMAGE_BUILD_CMD=${DOCKERBUILD} -f ${TOOLSPATH}/mockery/Dockerfile --build-arg GOLANG=${GOBUILDIMAGE} --build-arg MOCKERY_VERSION=${MOCKERY_VERSION} -t ${MOCKERY_IMAGENAME}:$(MOCKERY_VERSION) . -MOCKERY_IMAGE: - @if [ "$(shell ${DOCKERIMAGES} -q ${MOCKERY_IMAGENAME}:$(MOCKERY_VERSION) 2> /dev/null)" == "" ]; then \ - ${MOCKERY_IMAGE_BUILD_CMD} && echo "build mockery image successfully" || (echo "build mockery image failed" && exit 1) ; \ - fi - -gen_mocks: MOCKERY_IMAGE +gen_mocks: + $(call prepare_docker_image,${MOCKERY_IMAGENAME},${MOCKERY_VERSION},${MOCKERY_IMAGE_BUILD_CMD}) ${MOCKERY} go generate ./... mocks_check: gen_mocks diff --git a/api/v2.0/swagger.yaml b/api/v2.0/swagger.yaml index 85ab299a1..632b47c9f 100644 --- a/api/v2.0/swagger.yaml +++ b/api/v2.0/swagger.yaml @@ -26,6 +26,8 @@ paths: tags: - health operationId: getHealth + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: The health status of Harbor components @@ -39,6 +41,7 @@ paths: description: |- The Search endpoint returns information about the projects, repositories and helm charts offered at public status or related to the current logged in user. The response includes the project, repository list and charts in a proper display order. parameters: + - $ref: '#/parameters/requestId' - name: q in: query description: Search parameter for project and repository name. @@ -61,6 +64,8 @@ paths: tags: - statistic operationId: getStatistic + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: The statistic information @@ -77,6 +82,7 @@ paths: description: | This endpoint ping the available ldap service for test related configuration parameters. parameters: + - $ref: '#/parameters/requestId' - name: ldapconf in: body description: 'ldap configuration. support input ldap service configuration. If it is a empty request, will load current configuration from the system.' @@ -105,6 +111,7 @@ paths: description: | This endpoint searches the available ldap users based on related configuration parameters. Support searched by input ladp configuration, load configuration from the system and specific filter. parameters: + - $ref: '#/parameters/requestId' - name: username in: query type: string @@ -134,6 +141,7 @@ paths: description: | This endpoint adds the selected available ldap users to harbor based on related configuration parameters from the system. System will try to guess the user email address and realname, add to harbor user information. If have errors when import user, will return the list of importing failed uid and the failed reason. parameters: + - $ref: '#/parameters/requestId' - name: uid_list in: body description: The uid listed for importing. This list will check users validity of ldap service based on configuration from the system. @@ -166,6 +174,7 @@ paths: description: | This endpoint searches the available ldap groups based on related configuration parameters. support to search by groupname or groupdn. parameters: + - $ref: '#/parameters/requestId' - name: groupname in: query type: string @@ -3126,6 +3135,7 @@ paths: - replication operationId: listReplicationPolicies parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/query' - $ref: '#/parameters/sort' - $ref: '#/parameters/page' @@ -3162,6 +3172,7 @@ paths: - replication operationId: createReplicationPolicy parameters: + - $ref: '#/parameters/requestId' - name: policy in: body description: The replication policy @@ -3189,6 +3200,7 @@ paths: - replication operationId: getReplicationPolicy parameters: + - $ref: '#/parameters/requestId' - name: id in: path type: integer @@ -3213,6 +3225,7 @@ paths: - replication operationId: deleteReplicationPolicy parameters: + - $ref: '#/parameters/requestId' - name: id in: path type: integer @@ -3239,6 +3252,7 @@ paths: - replication operationId: updateReplicationPolicy parameters: + - $ref: '#/parameters/requestId' - name: id in: path type: integer @@ -3272,6 +3286,7 @@ paths: - replication operationId: listReplicationExecutions parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/sort' - $ref: '#/parameters/page' - $ref: '#/parameters/pageSize' @@ -3317,6 +3332,7 @@ paths: - replication operationId: startReplication parameters: + - $ref: '#/parameters/requestId' - name: execution in: body description: The ID of policy that the execution belongs to @@ -3342,6 +3358,7 @@ paths: - replication operationId: getReplicationExecution parameters: + - $ref: '#/parameters/requestId' - name: id in: path type: integer @@ -3368,6 +3385,7 @@ paths: - replication operationId: stopReplication parameters: + - $ref: '#/parameters/requestId' - name: id in: path type: integer @@ -3393,6 +3411,7 @@ paths: - replication operationId: listReplicationTasks parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/sort' - $ref: '#/parameters/page' - $ref: '#/parameters/pageSize' @@ -3442,6 +3461,7 @@ paths: produces: - text/plain parameters: + - $ref: '#/parameters/requestId' - name: id in: path type: integer @@ -3731,6 +3751,8 @@ paths: tags: - scanAll operationId: getLatestScanAllMetrics + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: OK @@ -3752,6 +3774,8 @@ paths: - scanAll operationId: getLatestScheduledScanAllMetrics deprecated: true + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: OK @@ -3773,6 +3797,8 @@ paths: This API is for retrieving general system info, this can be called by anonymous request. Some attributes will be omitted in the response when this API is called by anonymous request. tags: - systeminfo + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: Get general info successfully. @@ -3788,6 +3814,8 @@ paths: This endpoint is for retrieving system volume info that only provides for admin user. Note that the response only reflects the storage status of local disk. tags: - systeminfo + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: Get system volumes successfully. @@ -3811,6 +3839,8 @@ paths: - systeminfo produces: - application/octet-stream + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: Get default root certificate successfully. @@ -3833,6 +3863,7 @@ paths: - oidc operationId: pingOIDC parameters: + - $ref: '#/parameters/requestId' - name: endpoint in: body description: Request body for OIDC endpoint to be tested. @@ -3863,6 +3894,7 @@ paths: - gc operationId: getGCHistory parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/query' - $ref: '#/parameters/sort' - $ref: '#/parameters/page' @@ -3893,6 +3925,7 @@ paths: description: This endpoint let user get gc status filtered by specific ID. operationId: getGC parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/gcId' tags: - gc @@ -3915,6 +3948,7 @@ paths: description: This endpoint let user get gc job logs filtered by specific ID. operationId: getGCLog parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/gcId' tags: - gc @@ -3942,6 +3976,8 @@ paths: operationId: getGCSchedule tags: - gc + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: Get gc's schedule. @@ -3959,6 +3995,7 @@ paths: This endpoint is for update gc schedule. operationId: createGCSchedule parameters: + - $ref: '#/parameters/requestId' - name: schedule in: body required: true @@ -3986,6 +4023,7 @@ paths: This endpoint is for update gc schedule. operationId: updateGCSchedule parameters: + - $ref: '#/parameters/requestId' - name: schedule in: body required: true @@ -4012,6 +4050,8 @@ paths: operationId: getSystemCVEAllowlist tags: - SystemCVEAllowlist + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: Successfully retrieved the CVE allowlist. @@ -4029,6 +4069,7 @@ paths: tags: - SystemCVEAllowlist parameters: + - $ref: '#/parameters/requestId' - in: body name: allowlist description: The allowlist with new content @@ -4050,6 +4091,8 @@ paths: tags: - scanAll operationId: getScanAllSchedule + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: Get a schedule for the scan all job, which scans all of images in Harbor. @@ -4067,6 +4110,7 @@ paths: summary: Update scan all's schedule. description: This endpoint is for updating the schedule of scan all job, which scans all of images in Harbor. parameters: + - $ref: '#/parameters/requestId' - name: schedule in: body required: true @@ -4093,6 +4137,7 @@ paths: summary: Create a schedule or a manual trigger for the scan all job. description: This endpoint is for creating a schedule or a manual trigger for the scan all job, which scans all of images in Harbor. parameters: + - $ref: '#/parameters/requestId' - name: schedule in: body required: true @@ -4119,12 +4164,15 @@ paths: $ref: '#/responses/500' /ping: get: + operationId: getPing summary: Ping Harbor to check if it's alive. description: This API simply replies a pong to indicate the process to handle API is up, disregarding the health status of dependent components. tags: - ping produces: - text/plain + parameters: + - $ref: '#/parameters/requestId' responses: '200': description: The API server is alive @@ -4666,6 +4714,7 @@ paths: - scanner operationId: setScannerAsDefault parameters: + - $ref: '#/parameters/requestId' - name: registration_id in: path description: The scanner registration identifier. @@ -4883,6 +4932,7 @@ paths: description: | This endpoint let administrator of Harbor mark a registered user as removed.It actually won't be deleted from DB. parameters: + - $ref: '#/parameters/requestId' - name: user_id in: path type: integer @@ -4910,6 +4960,7 @@ paths: - user operationId: setUserSysAdmin parameters: + - $ref: '#/parameters/requestId' - name: user_id in: path type: integer @@ -4941,6 +4992,7 @@ paths: - user operationId: updateUserPassword parameters: + - $ref: '#/parameters/requestId' - name: user_id in: path type: integer @@ -4970,6 +5022,7 @@ paths: - user operationId: getCurrentUserPermissions parameters: + - $ref: '#/parameters/requestId' - name: scope in: query type: string @@ -5090,6 +5143,7 @@ paths: - label operationId: CreateLabel parameters: + - $ref: '#/parameters/requestId' - name: label in: body description: The json object of label. @@ -5122,6 +5176,7 @@ paths: - label operationId: GetLabelByID parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/labelId' responses: '200': @@ -5142,6 +5197,7 @@ paths: - label operationId: UpdateLabel parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/labelId' - name: label in: body @@ -5170,6 +5226,7 @@ paths: - label operationId: DeleteLabel parameters: + - $ref: '#/parameters/requestId' - $ref: '#/parameters/labelId' responses: '200': @@ -5851,12 +5908,12 @@ definitions: type: string format: date-time description: 'The start time of the scan process that generating report' - example: '2006-01-02T14:04:05' + example: '2006-01-02T14:04:05Z' end_time: type: string format: date-time description: 'The end time of the scan process that generating report' - example: '2006-01-02T15:04:05' + example: '2006-01-02T15:04:05Z' complete_percent: type: integer description: 'The complete percent of the scanning which value is between 0 and 100' @@ -5912,7 +5969,7 @@ definitions: op_time: type: string format: date-time - example: '2006-01-02T15:04:05' + example: '2006-01-02T15:04:05Z' description: The time when this operation is triggered. Metadata: type: object @@ -7372,7 +7429,7 @@ definitions: adapter: type: string description: Optional property to describe the name of the scanner registration - example: "Clair" + example: "Trivy" vendor: type: string description: Optional property to describe the vendor of the scanner registration @@ -8196,4 +8253,4 @@ definitions: type: integer format: int64 description: The total storage consumption of blobs, only be seen by the system admin - x-omitempty: false \ No newline at end of file + x-omitempty: false diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.ts index f8aa046c7..e57c97fde 100644 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.ts +++ b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.ts @@ -79,12 +79,14 @@ export class GcComponent implements OnInit { }, ONE_MINUTE); this.gcService.createGCSchedule({ - parameters: { - delete_untagged: this.shouldDeleteUntagged, - dry_run: false - }, schedule: { - type: ScheduleType.MANUAL + parameters: { + delete_untagged: this.shouldDeleteUntagged, + dry_run: false + }, + schedule: { + type: ScheduleType.MANUAL + } } }).subscribe( response => { @@ -99,12 +101,14 @@ export class GcComponent implements OnInit { dryRun() { this.dryRunOnGoing = true; this.gcService.createGCSchedule({ - parameters: { - delete_untagged: this.shouldDeleteUntagged, - dry_run: true - }, schedule: { - type: ScheduleType.MANUAL + parameters: { + delete_untagged: this.shouldDeleteUntagged, + dry_run: true + }, + schedule: { + type: ScheduleType.MANUAL + } } }) .pipe(finalize(() => this.dryRunOnGoing = false)) @@ -125,13 +129,15 @@ export class GcComponent implements OnInit { saveGcSchedule(cron: string) { if (this.originCron && this.originCron.type !== ScheduleType.NONE) {// no schedule, then create this.gcService.createGCSchedule({ - parameters: { - delete_untagged: this.shouldDeleteUntagged, - dry_run: false - }, schedule: { - type: GcComponent.getScheduleType(cron), - cron: cron + parameters: { + delete_untagged: this.shouldDeleteUntagged, + dry_run: false + }, + schedule: { + type: GcComponent.getScheduleType(cron), + cron: cron + } } }).subscribe( response => { @@ -145,13 +151,15 @@ export class GcComponent implements OnInit { ); } else { this.gcService.updateGCSchedule({ - parameters: { - delete_untagged: this.shouldDeleteUntagged, - dry_run: false - }, schedule: { - type: GcComponent.getScheduleType(cron), - cron: cron + parameters: { + delete_untagged: this.shouldDeleteUntagged, + dry_run: false + }, + schedule: { + type: GcComponent.getScheduleType(cron), + cron: cron + } } }).subscribe( response => { diff --git a/src/portal/src/app/base/left-side-nav/replication/replication/replication-tasks/replication-tasks.component.ts b/src/portal/src/app/base/left-side-nav/replication/replication/replication-tasks/replication-tasks.component.ts index 0431271bb..075acfae9 100644 --- a/src/portal/src/app/base/left-side-nav/replication/replication/replication-tasks/replication-tasks.component.ts +++ b/src/portal/src/app/base/left-side-nav/replication/replication/replication-tasks/replication-tasks.component.ts @@ -73,7 +73,9 @@ export class ReplicationTasksComponent implements OnInit, OnDestroy { getExecutionDetail(): void { this.inProgress = true; if (this.executionId) { - this.replicationService.getReplicationExecution(+this.executionId) + this.replicationService.getReplicationExecution({ + id: +this.executionId + }) .pipe(finalize(() => (this.inProgress = false))) .subscribe(res => { this.execution = res; @@ -136,8 +138,9 @@ export class ReplicationTasksComponent implements OnInit, OnDestroy { stopJob() { this.stopOnGoing = true; - this.replicationService.stopReplication(+this.executionId) - .subscribe(response => { + this.replicationService.stopReplication({ + id: +this.executionId + }).subscribe(response => { this.stopOnGoing = false; this.getExecutionDetail(); this.translate.get("REPLICATION.STOP_SUCCESS", { param: this.executionId }).subscribe((res: string) => { diff --git a/src/portal/src/app/services/routing-resolvers/replication-tasks-routing-resolver.service.ts b/src/portal/src/app/services/routing-resolvers/replication-tasks-routing-resolver.service.ts index 35373ff4f..9000b7a2c 100644 --- a/src/portal/src/app/services/routing-resolvers/replication-tasks-routing-resolver.service.ts +++ b/src/portal/src/app/services/routing-resolvers/replication-tasks-routing-resolver.service.ts @@ -33,8 +33,9 @@ export class ReplicationTasksRoutingResolverService implements Resolve { + return this.replicationService.getReplicationExecution({ + id: +executionId + }).pipe(map((res: ReplicationExecution) => { if (!res) { this.router.navigate(['/harbor', 'projects']); } diff --git a/src/portal/src/app/shared/components/label/create-edit-label/create-edit-label.component.ts b/src/portal/src/app/shared/components/label/create-edit-label/create-edit-label.component.ts index e07fbd4b0..ff4f206d4 100644 --- a/src/portal/src/app/shared/components/label/create-edit-label/create-edit-label.component.ts +++ b/src/portal/src/app/shared/components/label/create-edit-label/create-edit-label.component.ts @@ -137,8 +137,9 @@ export class CreateEditLabelComponent implements OnInit, OnDestroy { if (this.labelId <= 0) { this.labelModel.scope = this.scope; this.labelModel.project_id = this.projectId; - this.labelService.CreateLabel(this.labelModel) - .subscribe(res => { + this.labelService.CreateLabel({ + label: this.labelModel + }).subscribe(res => { this.inProgress = false; this.reload.emit(); this.labelModel = this.initLabel(); diff --git a/src/portal/src/app/shared/components/label/label.component.ts b/src/portal/src/app/shared/components/label/label.component.ts index dac3c1645..10950c3a7 100644 --- a/src/portal/src/app/shared/components/label/label.component.ts +++ b/src/portal/src/app/shared/components/label/label.component.ts @@ -186,7 +186,7 @@ export class LabelComponent implements OnInit { this.operationService.publishInfo(operMessage); return this.labelService - .DeleteLabel(target.id) + .DeleteLabel({labelId: target.id}) .pipe(map( response => { this.translateService.get('BATCH.DELETED_SUCCESS') diff --git a/tools/spectral/Dockerfile b/tools/spectral/Dockerfile new file mode 100644 index 000000000..d9fc51793 --- /dev/null +++ b/tools/spectral/Dockerfile @@ -0,0 +1,8 @@ +ARG GOLANG +FROM ${GOLANG} + +ARG SPECTRAL_VERSION +RUN curl -fsSL -o /usr/bin/spectral https://github.com/stoplightio/spectral/releases/download/$SPECTRAL_VERSION/spectral-linux && chmod +x /usr/bin/spectral + +ENTRYPOINT ["/usr/bin/spectral"] +CMD ["--version"] diff --git a/tools/spectral/functions/requireRequestId.js b/tools/spectral/functions/requireRequestId.js new file mode 100644 index 000000000..f13b60cb3 --- /dev/null +++ b/tools/spectral/functions/requireRequestId.js @@ -0,0 +1,13 @@ +module.exports = parameters => { + for (const param of parameters) { + if (param.name === 'X-Request-Id' && param.in === 'header') { + return + } + } + + return [ + { + message: 'X-Request-Id must be in "parameters".', + }, + ]; +};