goharbor / goharbor/harbor-cli

[discussion]: fixing Harbor API swagger spec gaps that cause cryptic CLI errors

Open
#1,029 1 comment 0 reactions 0 assignees View on GitHub
deps/go-client deps/harbor discussion enhancement
Dominant language
Go
Stars
163
Forks
211
Avg merge
1m
Merged PRs (30d)
1

Description

## Topic

Tracking progress: fixing Harbor API swagger spec gaps that cause cryptic CLI errors

## Context

While triaging open issues in this repo, a pattern emerged that explains a large class of confusing error messages users see. The go-swagger-generated client treats any HTTP status code not declared in Harbor's OpenAPI spec as a fatal error with a cryptic message:

```
response status code does not match any response statuses defined for this endpoint in the swagger spec (status NNN): {}
```

This completely hides the actual error Harbor is returning. A full scan of open and closed issues identified two dominant bug patterns:

**1. Swagger spec status code mismatches** — Harbor legitimately returns status codes (412, 422, 400) on certain endpoints, but those codes are absent from `api/v2.0/swagger.yaml`, so the go-swagger client panics with the message above instead of surfacing the real error.

Affected open issues: #981, and the root cause behind closed issues #419, #341, #557, #808, #941.

**2. Nil/unchecked API responses causing panics** — The generated client returns nil payloads or errors that callers silently discard, causing nil-pointer panics far from the actual API call. Still open: #1021, #1003, #997, #927, #933.

## Work Done So Far

### Step 1 — Fix swagger spec gaps in upstream Harbor

Branch: `fix/api-completeness` on my Harbor fork.

Two commits:

**Commit `2548cff`** — 15 swagger gaps (descriptions, responses, lint rules):
- Added 412 to `GET /users/current` (robot accounts → #941)
- Added 404 to `deleteProjectMember`, `UpdateImmuRule`, `DeleteImmuRule`
- Added 403+500 to `listAuditLogEventTypes`
- Added 400 to `listSchedules`, `getSchedulePaused`, `updateUserProfile`
- Added 401+500 to `getRentenitionMetadata`
- Added 500 to `pingOIDC`
- Removed inaccurate responses from several endpoints
- Added Spectral lint rules (`operation-description-required`, `operation-summary-required`) to prevent regression

**Commit `22b7611`** — complete swagger changes for harbor-cli well-known issues:
- Added 412 to `DELETE /projects/{name}/repositories/{repo}` (#419)
- Added 400, 422 to `PUT /system/configurations` (#557)
- Added 400, 422 to `listProjects` (#341)
- Added 422 to `listRepositories`, `listArtifacts`, `listTags`, `listArtifactsOfProject` (#341)
- Added 403, 404 to `GET /projects/{project_name_or_id}`
- Improved inline descriptions for 404/409/412 responses across project, artifact, tag, and user endpoints
- Improved global response descriptions (400, 401, 403, 404, 409, 412, 422, 500)
- Added `Error` definition example and `x-nullable: false` on error items

### Step 2 — Regenerate the go-client from the fixed spec

Because the CLI uses a generated go-client (`github.com/goharbor/go-client`) that encodes the spec at generation time, the CLI cannot benefit from spec fixes until the client is regenerated.

Forked the go-client to [`qcserestipy/harbor-go-client`](https://github.com/qcserestipy/harbor-go-client), regenerated the models from the fixed spec (temporarily disabling the upstream swagger.yaml pull in the generation pipeline), and published the result.

### Step 3 — Update harbor-cli to use the fixed client

Branch: `feat/api_changes` on this repo.

`go.mod` replaces the upstream client with the fork:
```
replace github.com/goharbor/go-client => github.com/qcserestipy/harbor-go-client v0.0.0-20260630110944-213bfae28890
```

CLI code was updated where the new model shapes required changes.

### Step 4 — Verified with a test script

Compared `harbor-main` (built from `main`) against `harbor-feat` (built from `feat/api_changes`) against a live Harbor instance (`demo.goharbor.io`).

**Test 1 — `repo delete` blocked by immutable tag rule (412)**

```
[main] Error: failed to delete repository: response status code does not match
any response statuses defined for this endpoint in the swagger spec (status 412): {}

[feature] Error: failed to delete repository: [DELETE /projects/{project_name}/repositories/{repository_name}]
[412] deleteRepositoryPreconditionFailed
{"errors":[{"code":"PRECONDITION","message":"the tag stable configured as immutable, cannot be deleted"}]}
```

**Test 2 — list endpoint with `page_size=99999` (422)**

Confirmed via curl that Harbor returns 422. The CLI has a client-side guard capping at 100, so neither binary reaches the server in normal usage — but the spec fix is in place for API consumers without the guard.

**Test 3 — `config apply` with `token_expiration: -9999` (400)**

```
[main] Error: failed to update Harbor configurations: response status code does not match
any response statuses defined for this endpoint in the swagger spec (status 400): {}

[feature] Error: failed to update Harbor configurations: [PUT /configurations][400]
updateConfigurationsBadRequest
{"errors":[{"code":"BAD_REQUEST","message":"the token_expiration value must be positive"}]}
```

## Possible Ideas / Thoughts

**What still needs to be done before a PR:**

1. The swagger spec changes need to be submitted upstream to `goharbor/harbor` first. The go-client regeneration and CLI changes are downstream of that.

2. The five nil-pointer / error-discarding open issues (#1021, #1003, #997, #927, #933) are not caused by spec gaps — they need targeted fixes in CLI Go code and should be tracked separately.

3. The test script (`test-swagger-gaps.sh`) in `feat/api_changes` can be reused or adapted as a regression check.

## Additional Information

- Harbor fork (swagger fixes): branch `fix/api-completeness` on `goharbor/harbor`
- go-client fork (regenerated models): [`qcserestipy/harbor-go-client`](https://github.com/qcserestipy/harbor-go-client)
- harbor-cli branch: `feat/api_changes` on this repo
- Test script: `test-swagger-gaps.sh` in `feat/api_changes`
- Full issue scan results: `harbor-api-issues.md` in `feat/api_changes`

Contributor guide

Open the contributing guide

Research direction

Start with api/v2.0/swagger.yaml and the listed Harbor endpoint responses, then review go.mod and the generated go-client replacement in the feat/api_changes branch. Run test-swagger-gaps.sh against a Harbor instance and compare the main and feature binaries. Done means the upstream spec, regenerated client, and CLI report Harbor's actual 400, 412, and 422 errors instead of cryptic status errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, openapi
Domain
api, cli
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.