Documentation
¶
Index ¶
- Constants
- Variables
- func DeterministicDummyDigest(counter int) digest.Digest
- func FlattenHeaders(hdr http.Header, extraHeaders ...map[string]string) map[string]string
- func GetReplicationPassword() string
- func MustExec(t *testing.T, db *keppel.DB, query string, args ...any)
- func ToJSON(x any) string
- func WithKeppelAPI(params *setupParams)
- func WithPeerAPI(params *setupParams)
- func WithPreviousIssuerKey(params *setupParams)
- func WithQuotas(params *setupParams)
- func WithRoundTripper(action func(*RoundTripper))
- func WithTrivyDouble(params *setupParams)
- func WithoutCurrentIssuerKey(params *setupParams)
- func WithoutRoundTripper(action func())
- type AccountRecordedByFederationDriver
- type AuthDriver
- func (d *AuthDriver) AuthenticateUser(ctx context.Context, userName, password string) (keppel.UserIdentity, *keppel.RegistryV2Error)
- func (d *AuthDriver) AuthenticateUserFromRequest(r *http.Request) (keppel.UserIdentity, *keppel.RegistryV2Error)
- func (d *AuthDriver) Init(ctx context.Context, rc *redis.Client) error
- func (d *AuthDriver) PluginTypeID() string
- type Bytes
- type ErrorCode
- type ErrorCodeWithMessage
- type FederationDriver
- func (d *FederationDriver) ClaimAccountName(ctx context.Context, account models.ReducedAccount, subleaseTokenSecret string) (keppel.ClaimResult, error)
- func (d *FederationDriver) FindPrimaryAccount(ctx context.Context, accountName models.AccountName) (string, error)
- func (d *FederationDriver) ForfeitAccountName(ctx context.Context, account models.ReducedAccount) error
- func (d *FederationDriver) Init(ctx context.Context, ad keppel.AuthDriver, cfg keppel.Configuration) error
- func (d *FederationDriver) IssueSubleaseTokenSecret(ctx context.Context, account models.ReducedAccount) (string, error)
- func (d *FederationDriver) PluginTypeID() string
- func (d *FederationDriver) RecordExistingAccount(ctx context.Context, account models.ReducedAccount, now time.Time) error
- type Image
- type ImageList
- type InboundCacheDriver
- func (d *InboundCacheDriver) Init(ctx context.Context, cfg keppel.Configuration) error
- func (d *InboundCacheDriver) LoadManifest(ctx context.Context, location models.ImageReference, now time.Time) (contents []byte, mediaType string, err error)
- func (d *InboundCacheDriver) PluginTypeID() string
- func (d *InboundCacheDriver) StoreManifest(ctx context.Context, location models.ImageReference, contents []byte, ...) error
- type OCIArgs
- type RoundTripper
- type Setup
- func (s Setup) ExpectBlobsExistInStorage(t *testing.T, blobs ...models.Blob)
- func (s Setup) ExpectBlobsMissingInStorage(t *testing.T, blobs ...models.Blob)
- func (s Setup) ExpectManifestsExistInStorage(t *testing.T, repoName string, manifests ...models.Manifest)
- func (s Setup) ExpectManifestsMissingInStorage(t *testing.T, manifests ...models.Manifest)
- func (s Setup) ExpectTrivyReportExistsInStorage(t *testing.T, manifest models.Manifest, format string, ...)
- func (s Setup) ExpectTrivyReportMissingInStorage(t *testing.T, manifest models.Manifest, format string)
- func (s Setup) GetAnonTokenHeaders(t *testing.T, repo string, scopes []string) http.Header
- func (s Setup) GetAnycastTokenHeaders(t *testing.T, scopes ...string) http.Header
- func (s Setup) GetDomainRemappedTokenHeaders(t *testing.T, accountName models.AccountName, scopes ...string) http.Header
- func (s Setup) GetTokenHeaders(t *testing.T, scopes ...string) http.Header
- func (s Setup) RespondTo(ctx context.Context, methodAndPath string, options ...httptest.RequestOption) httptest.Response
- type SetupOption
- type StorageIDGenerator
- type TrivyDouble
Constants ¶
const ( // VersionHeaderKey is the standard version header name included in all // Registry v2 API responses. VersionHeaderKey = "Docker-Distribution-Api-Version" // VersionHeaderValue is the standard version header value included in all // Registry v2 API responses. VersionHeaderValue = "registry/2.0" )
TODO: make private once assert.HTTPRequest is removed
const UnitTestAnycastIssuerEd25519PrivateKey = `-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIMk7vAS28DlAzYWG9yktmmAnla+wvvTo/Ah6qmXG6E+S
-----END PRIVATE KEY-----`
UnitTestAnycastIssuerEd25519PrivateKey is an ed25519 private key that can be used as KEPPEL_ISSUER_KEY in unit tests. DO NOT USE IN PRODUCTION.
const UnitTestAnycastIssuerRSAPrivateKey = `` /* 3242-byte string literal not displayed */
UnitTestAnycastIssuerRSAPrivateKey is an RSA private key that can be used as KEPPEL_ANYCAST_ISSUER_KEY in unit tests. DO NOT USE IN PRODUCTION.
const UnitTestIssuerEd25519PrivateKey = `-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIJF8IUp7t4h64Xm9WDPtThzRHiQY5guceFs4z8QDrMQ0
-----END PRIVATE KEY-----`
UnitTestIssuerEd25519PrivateKey is an ed25519 private key that can be used as KEPPEL_ISSUER_KEY in unit tests. DO NOT USE IN PRODUCTION.
const UnitTestIssuerRSAPrivateKey = `` /* 3246-byte string literal not displayed */
UnitTestIssuerRSAPrivateKey is an RSA private key that can be used as KEPPEL_ISSUER_KEY in unit tests. DO NOT USE IN PRODUCTION.
Variables ¶
var ( // CADFReasonOK is a helper to make cadf.Event literals shorter. CADFReasonOK = cadf.Reason{ ReasonType: "HTTP", ReasonCode: "200", } )
var VersionHeader = map[string]string{VersionHeaderKey: VersionHeaderValue}
VersionHeader is the standard version header included in all Registry v2 API responses.
TODO: remove once assert.HTTPRequest is removed
Functions ¶
func DeterministicDummyDigest ¶
DeterministicDummyDigest creates a digest from the counter input, which can be used for testing.
func FlattenHeaders ¶
FlattenHeaders converts a http.Header into map[string]string. This is a temporary helper function to support old assert.HTTPRequest usage.
TODO: when refactoring callsites into httptest.Handler.RespondTo(), convert: - calls without variadic arguments into just `httptest.WithHeaders(hdr)` - calls with variadic arguments into `httptest.WithHeaders(hdr)` plus one `httptest.WithHeader(key, value)` per extra header
TODO: remove once refactoring from assert.HTTPRequest to httptest.Handler.RespondTo() is complete
func GetReplicationPassword ¶
func GetReplicationPassword() string
GetReplicationPassword returns the password that the secondary registry can use to replicate from the primary registry.
func MustExec ¶
MustExec is a test helper function that executes a DB query and fails the test if it returns an error.
func ToJSON ¶
ToJSON is a more compact equivalent of json.Marshal() that panics on error instead of returning it, and which returns string instead of []byte.
func WithKeppelAPI ¶
func WithKeppelAPI(params *setupParams)
WithKeppelAPI is a SetupOption that enables the Keppel API.
func WithPeerAPI ¶
func WithPeerAPI(params *setupParams)
WithPeerAPI is a SetupOption that enables the peer API.
func WithPreviousIssuerKey ¶
func WithPreviousIssuerKey(params *setupParams)
WithPreviousIssuerKey is a SetupOption that will add the "previous" set of test issuer keys.
func WithQuotas ¶
func WithQuotas(params *setupParams)
WithQuotas is a SetupOption that sets up ample quota for all configured accounts.
func WithRoundTripper ¶
func WithRoundTripper(action func(*RoundTripper))
WithRoundTripper sets up a RoundTripper instance as the default HTTP transport for the duration of the given action.
func WithTrivyDouble ¶
func WithTrivyDouble(params *setupParams)
WithTrivyDouble is a SetupOption that sets up a TrivyDouble at trivy.example.org.
func WithoutCurrentIssuerKey ¶
func WithoutCurrentIssuerKey(params *setupParams)
WithoutCurrentIssuerKey is a SetupOption that will not add the "current" set of test issuer keys. Tokens will be issued with the "previous" set of issuer keys instead, so WithPreviousIssuerKey must be given as well.
func WithoutRoundTripper ¶
func WithoutRoundTripper(action func())
WithoutRoundTripper can be used during WithRoundTripper() to temporarily revert back to the
Types ¶
type AccountRecordedByFederationDriver ¶
type AccountRecordedByFederationDriver struct {
Account models.ReducedAccount
RecordedAt time.Time
}
AccountRecordedByFederationDriver appears in type FederationDriver.
type AuthDriver ¶
type AuthDriver struct {
// for AuthenticateUser
ExpectedUserName string `json:"-"`
ExpectedPassword string `json:"-"`
GrantedPermissions string `json:"-"`
}
AuthDriver (type "unittest") is a keppel.AuthDriver for unit tests.
func (*AuthDriver) AuthenticateUser ¶
func (d *AuthDriver) AuthenticateUser(ctx context.Context, userName, password string) (keppel.UserIdentity, *keppel.RegistryV2Error)
AuthenticateUser implements the keppel.AuthDriver interface.
func (*AuthDriver) AuthenticateUserFromRequest ¶
func (d *AuthDriver) AuthenticateUserFromRequest(r *http.Request) (keppel.UserIdentity, *keppel.RegistryV2Error)
AuthenticateUserFromRequest implements the keppel.AuthDriver interface.
func (*AuthDriver) PluginTypeID ¶
func (d *AuthDriver) PluginTypeID() string
PluginTypeID implements the keppel.AuthDriver interface.
type Bytes ¶
type Bytes struct {
Annotations map[string]string
Contents []byte
Digest digest.Digest
MediaType string
}
Bytes groups a bytestring with its digest.
func GenerateExampleLayer ¶
GenerateExampleLayer generates a blob of 1 MiB that can be used like an image layer when constructing image manifests for unit tests. The contents are generated deterministically from the given seed.
func GenerateExampleLayerSize ¶
GenerateExampleLayerSize generates a blob of a configurable size that can be used like an image layer when constructing image manifests for unit tests. The contents are generated deterministically from the given seed.
func NewBytesFromFile ¶
NewBytesFromFile creates a Bytes instance with the contents of the given file.
func (Bytes) MustUpload ¶
MustUpload uploads the blob via the Registry V2 API.
`h` must serve the Registry V2 API. `token` must be a Bearer token capable of pushing into the specified repo.
type ErrorCode ¶
type ErrorCode keppel.RegistryV2ErrorCode
ErrorCode wraps keppel.RegistryV2ErrorCode with an implementation of the assert.HTTPResponseBody and the jsonmatch.Diffable interfaces.
func (ErrorCode) AssertResponseBody ¶
AssertResponseBody implements the assert.HTTPResponseBody interface.
TODO: remove after all assert.HTTPRequests usage has been replaced with httptest.Handler.RespondTo()
type ErrorCodeWithMessage ¶
type ErrorCodeWithMessage struct {
Code keppel.RegistryV2ErrorCode
Message string
}
ErrorCodeWithMessage extends ErrorCode with an expected detail message.
func (ErrorCodeWithMessage) AssertResponseBody ¶
func (e ErrorCodeWithMessage) AssertResponseBody(t *testing.T, requestInfo string, responseBody []byte) bool
AssertResponseBody implements the assert.HTTPResponseBody interface.
TODO: remove after all assert.HTTPRequests usage has been replaced with httptest.Handler.RespondTo()
func (ErrorCodeWithMessage) DiffAgainst ¶
func (e ErrorCodeWithMessage) DiffAgainst(buf []byte) []jsonmatch.Diff
DiffAgainst implements the jsonmatch.Diffable interface.
type FederationDriver ¶
type FederationDriver struct {
APIPublicHostName string
ClaimFailsBecauseOfUserError bool
ClaimFailsBecauseOfServerError bool
ForfeitFails bool
NextSubleaseTokenSecretToIssue string
ValidSubleaseTokenSecrets map[models.AccountName]string
RecordedAccounts []AccountRecordedByFederationDriver
}
FederationDriver (driver ID "unittest") is a keppel.FederationDriver for unit tests.
func (*FederationDriver) ClaimAccountName ¶
func (d *FederationDriver) ClaimAccountName(ctx context.Context, account models.ReducedAccount, subleaseTokenSecret string) (keppel.ClaimResult, error)
ClaimAccountName implements the keppel.FederationDriver interface.
func (*FederationDriver) FindPrimaryAccount ¶
func (d *FederationDriver) FindPrimaryAccount(ctx context.Context, accountName models.AccountName) (string, error)
FindPrimaryAccount implements the keppel.FederationDriver interface.
func (*FederationDriver) ForfeitAccountName ¶
func (d *FederationDriver) ForfeitAccountName(ctx context.Context, account models.ReducedAccount) error
ForfeitAccountName implements the keppel.FederationDriver interface.
func (*FederationDriver) Init ¶
func (d *FederationDriver) Init(ctx context.Context, ad keppel.AuthDriver, cfg keppel.Configuration) error
Init implements the keppel.FederationDriver interface.
func (*FederationDriver) IssueSubleaseTokenSecret ¶
func (d *FederationDriver) IssueSubleaseTokenSecret(ctx context.Context, account models.ReducedAccount) (string, error)
IssueSubleaseTokenSecret implements the keppel.FederationDriver interface.
func (*FederationDriver) PluginTypeID ¶
func (d *FederationDriver) PluginTypeID() string
PluginTypeID implements the keppel.FederationDriver interface.
func (*FederationDriver) RecordExistingAccount ¶
func (d *FederationDriver) RecordExistingAccount(ctx context.Context, account models.ReducedAccount, now time.Time) error
RecordExistingAccount implements the keppel.FederationDriver interface.
type Image ¶
Image contains all the pieces of a Docker image. The Layers and Config must be uploaded to the registry as blobs.
func GenerateImage ¶
GenerateImage makes an Image from the given bytes in a deterministic manner.
func GenerateImageWithCustomConfig ¶
GenerateImageWithCustomConfig is like GenerateImage, but allows customizing the contents of the image config. The supplied change function will be called on the default config, and the result will be used as the config blob.
func GenerateOCIImage ¶
GenerateOCIImage creates an OCI image from the given arguments. The config blob to be stored in the manifest is serialized directly from the given arguments.
func (Image) DigestRef ¶
func (i Image) DigestRef() models.ManifestReference
DigestRef returns the ManifestReference for this manifest's digest.
func (Image) ImageRef ¶
func (i Image) ImageRef(s Setup, repo models.Repository) models.ImageReference
ImageRef returns the ImageReference for this images.
func (Image) MustUpload ¶
func (i Image) MustUpload(t *testing.T, s Setup, repo models.Repository, tagName string) models.Manifest
MustUpload uploads the image via the Registry V2 API. This also uploads all referenced blobs that do not exist in the DB yet.
`tagName` may be empty if the image is to be uploaded without tagging.
type ImageList ¶
ImageList contains all the pieces of a multi-architecture Docker image. This type is used for testing the behavior of Keppel with manifests that reference other manifests.
func GenerateImageList ¶
GenerateImageList makes an ImageList containing the given images in a deterministic manner.
func (ImageList) DigestRef ¶
func (l ImageList) DigestRef() models.ManifestReference
DigestRef returns the ManifestReference for this manifest's digest.
func (ImageList) ImageRef ¶
func (l ImageList) ImageRef(s Setup, repo models.Repository) models.ImageReference
ImageRef returns the ImageReference for this ImageList.
func (ImageList) MustUpload ¶
func (l ImageList) MustUpload(t *testing.T, s Setup, repo models.Repository, tagName string) models.Manifest
MustUpload uploads the image list via the Registry V2 API. This also uploads all referenced images that do not exist in the DB yet.
`tagName` may be empty if the image is to be uploaded without tagging.
type InboundCacheDriver ¶
type InboundCacheDriver struct {
MaxAge time.Duration
Entries map[models.ImageReference]inboundCacheEntry
}
InboundCacheDriver (driver ID "unittest") is a keppel.InboundCacheDriver for unit tests. It remembers all manifests ever pushed into it in-memory (which is a really bad idea for an production driver because of the potentially unbounded memory footprint).
func (*InboundCacheDriver) Init ¶
func (d *InboundCacheDriver) Init(ctx context.Context, cfg keppel.Configuration) error
Init implements the keppel.InboundCacheDriver interface.
func (*InboundCacheDriver) LoadManifest ¶
func (d *InboundCacheDriver) LoadManifest(ctx context.Context, location models.ImageReference, now time.Time) (contents []byte, mediaType string, err error)
LoadManifest implements the keppel.InboundCacheDriver interface.
func (*InboundCacheDriver) PluginTypeID ¶
func (d *InboundCacheDriver) PluginTypeID() string
PluginTypeID implements the keppel.InboundCacheDriver interface.
func (*InboundCacheDriver) StoreManifest ¶
func (d *InboundCacheDriver) StoreManifest(ctx context.Context, location models.ImageReference, contents []byte, mediaType string, now time.Time) error
StoreManifest implements the keppel.InboundCacheDriver interface.
type OCIArgs ¶
type OCIArgs struct {
Config map[string]any
ConfigMediaType string
Annotations map[string]string
ArtifactType string
SubjectDigest digest.Digest
}
OCIArgs are all relevant arguments for creating an OCIImage. It appears in GenerateOCIImage().
type RoundTripper ¶
RoundTripper is a http.RoundTripper that redirects some domains to http.Handler instances.
type Setup ¶
type Setup struct {
// fields that are always set
Config keppel.Configuration
DB *keppel.DB
Clock *mock.Clock
SIDGenerator *StorageIDGenerator
Auditor *audittools.MockAuditor
AD *AuthDriver
AMD *basic.AccountManagementDriver
FD *FederationDriver
SD *trivial.StorageDriver
ICD *InboundCacheDriver
Handler http.Handler
Ctx context.Context //nolint: containedctx // only used in tests
Registry *prometheus.Registry
// fields that are only set if the respective With... setup option is included
TrivyDouble *TrivyDouble
// fields that are filled by WithAccount and WithRepo (in order)
Accounts []models.Account
Repos []models.Repository
// contains filtered or unexported fields
}
Setup contains all the pieces that are needed for most tests.
func NewSetup ¶
func NewSetup(t testing.TB, opts ...SetupOption) Setup
NewSetup prepares most or all pieces of Keppel for a test.
func (Setup) ExpectBlobsExistInStorage ¶
ExpectBlobsExistInStorage is a test assertion.
func (Setup) ExpectBlobsMissingInStorage ¶
ExpectBlobsMissingInStorage is a test assertion.
func (Setup) ExpectManifestsExistInStorage ¶
func (s Setup) ExpectManifestsExistInStorage(t *testing.T, repoName string, manifests ...models.Manifest)
ExpectManifestsExistInStorage is a test assertion.
func (Setup) ExpectManifestsMissingInStorage ¶
ExpectManifestsMissingInStorage is a test assertion.
func (Setup) ExpectTrivyReportExistsInStorage ¶
func (s Setup) ExpectTrivyReportExistsInStorage(t *testing.T, manifest models.Manifest, format string, contents assert.HTTPResponseBody)
ExpectTrivyReportExistsInStorage is a test assertion.
func (Setup) ExpectTrivyReportMissingInStorage ¶
func (s Setup) ExpectTrivyReportMissingInStorage(t *testing.T, manifest models.Manifest, format string)
ExpectTrivyReportMissingInStorage is a test assertion.
func (Setup) GetAnonTokenHeaders ¶
GetAnonTokenHeaders obtains an anonymous token for use with the Registry V2 API.
`scopes` is a list of token scopes, e.g. "repository:test1/foo:pull". The necessary permissions will be inferred from the given scopes.
The return value contains the `Authorization` header for this token.
func (Setup) GetAnycastTokenHeaders ¶
GetAnycastTokenHeaders is like GetTokenHeaders, but instead returns a token for the anycast endpoint.
The return value contains the `Authorization` header for this token, as well as `X-Forwarded-*` headers that select the anycast API.
func (Setup) GetDomainRemappedTokenHeaders ¶
func (s Setup) GetDomainRemappedTokenHeaders(t *testing.T, accountName models.AccountName, scopes ...string) http.Header
GetDomainRemappedTokenHeaders is like GetTokenHeaders, but instead returns a token for a domain-remapped API.
The return value contains the `Authorization` header for this token, as well as `X-Forwarded-*` headers that select the domain-remapped API.
func (Setup) GetTokenHeaders ¶
GetTokenHeaders obtains a token for use with the Registry V2 API.
`scopes` is a list of token scopes, e.g. "repository:test1/foo:pull". The necessary permissions will be inferred from the given scopes, and a dummy UserIdentity object for the user called "correctusername" will be embedded in the token.
The return value contains the `Authorization` header for this token.
func (Setup) RespondTo ¶
func (s Setup) RespondTo(ctx context.Context, methodAndPath string, options ...httptest.RequestOption) httptest.Response
RespondTo is like s.handler.RespondTo(), but also checks the following universal response properties:
- Requests for endpoints in the OCI Distribution API (any path at or below /v2/) must always include the response header "Docker-Distribution-Api-Version: registry/2.0", even for error responses.
This saves the trouble of having to duplicate these checks hundreds of times.
type SetupOption ¶
type SetupOption func(*setupParams)
SetupOption is an option that can be given to NewSetup().
func IsSecondaryTo ¶
func IsSecondaryTo(s *Setup) SetupOption
IsSecondaryTo is a SetupOption that configures registry-secondary.example.org instead of registry.example.org. If a non-nil Setup instance is given, that's the Setup for the corresponding primary instance, and both sides will be configured to peer with each other.
func WithAccount ¶
func WithAccount(account models.Account) SetupOption
WithAccount is a SetupOption that adds the given keppel.Account to the DB during NewSetup().
func WithAnycast ¶
func WithAnycast(withAnycast bool) SetupOption
WithAnycast is a SetupOption that fills the anycast fields in keppel.Configuration if true is given.
func WithRateLimitEngine ¶
func WithRateLimitEngine(rle *keppel.RateLimitEngine) SetupOption
WithRateLimitEngine is a SetupOption to use a RateLimitEngine in enabled APIs.
func WithRepo ¶
func WithRepo(repo models.Repository) SetupOption
WithRepo is a SetupOption that adds the given keppel.Repository to the DB during NewSetup().
type StorageIDGenerator ¶
type StorageIDGenerator struct {
// contains filtered or unexported fields
}
StorageIDGenerator provides realistic-looking, but deterministic storage IDs for unit tests.
func (*StorageIDGenerator) Next ¶
func (g *StorageIDGenerator) Next() string
Next returns the next storage ID.
type TrivyDouble ¶
type TrivyDouble struct {
T *testing.T
ReportError map[models.ImageReference]bool
ReportFixtures map[models.ImageReference]string
}
TrivyDouble acts as a test double for a Trivy API.
func (*TrivyDouble) AddTo ¶
func (t *TrivyDouble) AddTo(r *mux.Router)
AddTo implements the api.API interface.