mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 18:51:32 +00:00
21aeed4f4e
Phase 0 closure (Path B2, post-rewrite):
addlicense sweep — adds the canonical certctl LLC copyright + BUSL-1.1
SPDX header to every production Go file. Template:
// Copyright 2026 certctl LLC. All rights reserved.
// SPDX-License-Identifier: BUSL-1.1
Coverage: 338 / 338 production Go files (cmd/ + internal/, excluding
*_test.go and **/testdata/**). Pre-sweep coverage was 22 / 338 (6.5%);
post-sweep is 338 / 338 (100%).
Normalized 22 pre-existing legacy headers (`// Copyright (c) certctl`
+ `// SPDX-License-Identifier: BSL-1.1`) and 1 file using a
`Certctl Contributors` attribution. The legacy SPDX ID `BSL-1.1`
is non-standard; the official SPDX identifier for Business Source
License 1.1 is `BUSL-1.1` (capital U). All 338 files now share the
canonical form.
Generated via:
addlicense -c "certctl LLC" -y 2026 \
-f cowork/legal/copyright-header.tpl \
-ignore '**/testdata/**' -ignore '**/*_test.go' \
cmd/ internal/
Verification:
find cmd internal -name '*.go' -not -name '*_test.go' \
-not -path '*/testdata/*' \
-exec grep -L '^// Copyright 2026 certctl LLC' {} \; | wc -l
Returns: 0
gofmt clean. Header additions are comments only, no compile impact.
Closes: cowork/certctl-architecture-diligence-audit.html#fix-RED-4
55 lines
2.5 KiB
Go
55 lines
2.5 KiB
Go
// Copyright 2026 certctl LLC. All rights reserved.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package domain
|
|
|
|
// BulkReassignmentRequest is the input to POST /api/v1/certificates/bulk-reassign.
|
|
//
|
|
// L-2 closure (cat-l-8a1fb258a38a): the GUI used to loop
|
|
// `await updateCertificate(id, { owner_id: ownerId })` over the selection
|
|
// at `web/src/pages/CertificatesPage.tsx::handleReassign`. Post-L-2 it
|
|
// POSTs once.
|
|
//
|
|
// Narrower than BulkRenewalCriteria — the operator workflow is "I have N
|
|
// certs selected and I want them all owned by Alice now". Criteria-mode
|
|
// reassignment doesn't have a strong use case (operators query first,
|
|
// then reassign by ID), so the request is IDs-only. OwnerID is required;
|
|
// TeamID is optional and the cert's team_id is updated only when TeamID
|
|
// is non-empty (matches the existing per-cert PUT behaviour where empty
|
|
// fields leave the existing value unchanged).
|
|
type BulkReassignmentRequest struct {
|
|
CertificateIDs []string `json:"certificate_ids"`
|
|
OwnerID string `json:"owner_id"`
|
|
TeamID string `json:"team_id,omitempty"`
|
|
}
|
|
|
|
// IsEmpty returns true if no IDs are provided. The service layer rejects
|
|
// empty IDs with a 400 — explicit-IDs is the only selection mode for
|
|
// reassignment (no criteria-mode). Naming mirrors BulkRevocationCriteria
|
|
// + BulkRenewalCriteria.IsEmpty so the validate-and-reject pattern is
|
|
// the same across all three bulk endpoints.
|
|
func (r BulkReassignmentRequest) IsEmpty() bool {
|
|
return len(r.CertificateIDs) == 0
|
|
}
|
|
|
|
// BulkReassignmentResult mirrors BulkRevocationResult / BulkRenewalResult
|
|
// envelope shape so the frontend's bulk-result rendering is one helper.
|
|
//
|
|
// Counters semantics:
|
|
// - TotalMatched: number of certs resolved from CertificateIDs
|
|
// - TotalReassigned: number where owner_id (and optionally team_id)
|
|
// was actually mutated
|
|
// - TotalSkipped: certs already owned by the target OwnerID — no-op
|
|
// skip rather than a fake "succeeded" count, so operators see "5 of
|
|
// your 10 selections were no-ops" without triaging fake errors
|
|
// - TotalFailed: certs where the per-cert update returned an error
|
|
// (e.g., the cert no longer exists, the repo update failed)
|
|
// - Errors: per-cert error details for the failure path
|
|
type BulkReassignmentResult struct {
|
|
TotalMatched int `json:"total_matched"`
|
|
TotalReassigned int `json:"total_reassigned"`
|
|
TotalSkipped int `json:"total_skipped"`
|
|
TotalFailed int `json:"total_failed"`
|
|
Errors []BulkOperationError `json:"errors,omitempty"`
|
|
}
|