diff --git a/README.md b/README.md
index c0a37b47b5..319e58fb4c 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ At the moment, the following artifacts kinds are supported *(with plans to suppo
- [Argo templates](https://argoproj.github.io/argo-workflows/)
- [Backstage plugins](https://backstage.io)
+- [Bootable containers](https://containers.github.io/bootc/)
- [Containers images](https://opencontainers.org)
- [CoreDNS plugins](https://coredns.io/)
- [Falco configurations](https://falco.org/)
diff --git a/charts/artifact-hub/Chart.yaml b/charts/artifact-hub/Chart.yaml
index 46d627041a..b1a8a4951f 100644
--- a/charts/artifact-hub/Chart.yaml
+++ b/charts/artifact-hub/Chart.yaml
@@ -2,7 +2,7 @@ apiVersion: v2
name: artifact-hub
description: Artifact Hub is a web-based application that enables finding, installing, and publishing Cloud Native packages.
type: application
-version: 1.21.0-4
+version: 1.21.0-5
appVersion: 1.20.0
kubeVersion: ">= 1.19.0-0"
home: https://artifacthub.io
@@ -33,6 +33,7 @@ keywords:
- meshery
- opencost
- radius
+ - bootable containers
maintainers:
- name: Sergio
email: tegioz@icloud.com
diff --git a/charts/artifact-hub/values.schema.json b/charts/artifact-hub/values.schema.json
index 821c8d9970..bcd3080bbb 100644
--- a/charts/artifact-hub/values.schema.json
+++ b/charts/artifact-hub/values.schema.json
@@ -1224,7 +1224,7 @@
},
"repositoriesKinds": {
"title": "Repositories kinds to process ([] = all)",
- "description": "The following kinds are supported at the moment: falco, helm, olm, opa, tbaction, krew, helm-plugin, tekton-task, keda-scaler, coredns, keptn, tekton-pipeline, container, kubewarden, gatekeeper, kyverno, knative-client-plugin, backstage, argo-template, kubearmor, kcl, headlamp, inspektor-gadget, tekton-stepaction, meshery, opencost, radius",
+ "description": "The following kinds are supported at the moment: falco, helm, olm, opa, tbaction, krew, helm-plugin, tekton-task, keda-scaler, coredns, keptn, tekton-pipeline, container, kubewarden, gatekeeper, kyverno, knative-client-plugin, backstage, argo-template, kubearmor, kcl, headlamp, inspektor-gadget, tekton-stepaction, meshery, opencost, radius, bootc",
"type": "array",
"items": {
"type": "string"
diff --git a/cmd/ah/lint.go b/cmd/ah/lint.go
index 237ea366f2..fb537762bc 100644
--- a/cmd/ah/lint.go
+++ b/cmd/ah/lint.go
@@ -97,7 +97,7 @@ func newLintCmd() *cobra.Command {
return lint(opts, &output{cmd.OutOrStdout()})
},
}
- lintCmd.Flags().StringVarP(&opts.kind, "kind", "k", "helm", "repository kind: argo-template, backstage, coredns, falco, gatekeeper, headlamp, helm, helm-plugin, inspektor-gadget, kcl, keda-scaler, keptn, knative-client-plugin, krew, kubearmor, kubewarden, kyverno, meshery, olm, opa, opencost, radius, tbaction, tekton-pipeline, tekton-stepaction, tekton-task")
+ lintCmd.Flags().StringVarP(&opts.kind, "kind", "k", "helm", "repository kind: argo-template, backstage, bootc, coredns, falco, gatekeeper, headlamp, helm, helm-plugin, inspektor-gadget, kcl, keda-scaler, keptn, knative-client-plugin, krew, kubearmor, kubewarden, kyverno, meshery, olm, opa, opencost, radius, tbaction, tekton-pipeline, tekton-stepaction, tekton-task")
lintCmd.Flags().StringVarP(&opts.path, "path", "p", ".", "repository's packages path")
lintCmd.Flags().StringVarP(&opts.tektonVersioning, "tekton-versioning", "", hub.TektonDirBasedVersioning, "tekton versioning option: directory, git")
return lintCmd
@@ -119,6 +119,7 @@ func lint(opts *lintOptions, out *output) error {
case
hub.ArgoTemplate,
hub.Backstage,
+ hub.Bootc,
hub.CoreDNS,
hub.Falco,
hub.Gatekeeper,
@@ -747,6 +748,7 @@ func (out *output) printPkgDetails(pkg *hub.Package) {
case
hub.ArgoTemplate,
hub.Backstage,
+ hub.Bootc,
hub.CoreDNS,
hub.Falco,
hub.Gatekeeper,
diff --git a/database/migrations/schema/062_bootable_containers.sql b/database/migrations/schema/062_bootable_containers.sql
new file mode 100644
index 0000000000..d85816c513
--- /dev/null
+++ b/database/migrations/schema/062_bootable_containers.sql
@@ -0,0 +1,5 @@
+insert into repository_kind values (27, 'Bootable containers');
+
+---- create above / drop below ----
+
+delete from repository_kind where repository_kind_id = 27;
diff --git a/database/tests/schema/schema.sql b/database/tests/schema/schema.sql
index a58b035c70..89b3a44f57 100644
--- a/database/tests/schema/schema.sql
+++ b/database/tests/schema/schema.sql
@@ -569,7 +569,8 @@ select results_eq(
(23, 'Tekton stepactions'),
(24, 'Meshery designs'),
(25, 'OpenCost plugins'),
- (26, 'Radius recipes')
+ (26, 'Radius recipes'),
+ (27, 'Bootable containers')
$$,
'Repository kinds should exist'
);
diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml
index c8671a4f5d..7e337ea4a3 100644
--- a/docs/api/openapi.yaml
+++ b/docs/api/openapi.yaml
@@ -1161,6 +1161,29 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
+ "/packages/bootc/{repoName}/{packageName}":
+ get:
+ tags:
+ - Packages
+ summary: Get package details
+ description: Get package details
+ operationId: getBootableContainersDetails
+ parameters:
+ - $ref: "#/components/parameters/RepoNameParam"
+ - $ref: "#/components/parameters/PackageNameParam"
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/BootableContainer"
+ "404":
+ $ref: "#/components/responses/NotFoundResponse"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
"/packages/container/{repoName}/{packageName}":
get:
tags:
@@ -1785,6 +1808,30 @@ paths:
$ref: "#/components/responses/TooManyRequests"
"500":
$ref: "#/components/responses/InternalServerError"
+ "/packages/bootc/{repoName}/{packageName}/{version}":
+ get:
+ tags:
+ - Packages
+ summary: Get package version details
+ description: Get package version details
+ operationId: getBootableContainersVersionDetails
+ parameters:
+ - $ref: "#/components/parameters/RepoNameParam"
+ - $ref: "#/components/parameters/PackageNameParam"
+ - $ref: "#/components/parameters/VersionParam"
+ responses:
+ "200":
+ description: ""
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/BootableContainer"
+ "404":
+ $ref: "#/components/responses/NotFoundResponse"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
"/packages/container/{repoName}/{packageName}/{version}":
get:
tags:
@@ -4052,6 +4099,8 @@ components:
example: "1.5.0"
BackstagePlugin:
$ref: "#/components/schemas/Package"
+ BootableContainer:
+ $ref: "#/components/schemas/Package"
ContainerImage:
allOf:
- $ref: "#/components/schemas/Package"
@@ -5049,6 +5098,12 @@ components:
- 19
- 20
- 21
+ - 22
+ - 23
+ - 24
+ - 25
+ - 26
+ - 27
description: |
Repository kind:
* `0` - Helm charts
@@ -5078,6 +5133,7 @@ components:
* `24` - Meshery designs
* `25` - Opencost plugins
* `26` - Radius recipes
+ * `27` - Bootable containers
RepositoryKindParam:
type: string
enum:
@@ -5108,6 +5164,7 @@ components:
- meshery
- opencost
- radius
+ - bootc
description: |
Repository kind name:
* `helm` - Helm charts
@@ -5137,6 +5194,7 @@ components:
* `meshery` - Meshery designs
* `opencost` - Opencost plugins
* `radius` - Radius recipes
+ * `bootc` - Bootable containers
RepositorySummary:
type: object
required:
@@ -5683,6 +5741,7 @@ components:
* `24` - Meshery designs
* `25` - Opencost plugins
* `26` - Radius recipes
+ * `27` - Bootable containers
PackageNameParam:
in: path
name: packageName
diff --git a/docs/bootable_containers_repositories.md b/docs/bootable_containers_repositories.md
new file mode 100644
index 0000000000..68d30726ee
--- /dev/null
+++ b/docs/bootable_containers_repositories.md
@@ -0,0 +1,51 @@
+## Bootable containers repositories
+
+Bootable containers repositories are expected to be hosted in GitHub, GitLab or Bitbucket repos. When adding your repository to Artifact Hub, the url used **must** follow the following format:
+
+- `https://github.com/user/repo[/path/to/packages]`
+- `https://gitlab.com/user/repo[/path/to/packages]`
+- `https://bitbucket.org/user/repo[/path/to/packages]`
+
+By default the `master` branch is used, but it's possible to specify a different one from the UI.
+
+*Please NOTE that the repository URL used when adding the repository to Artifact Hub **must NOT** contain the git hosting platform specific parts, like **tree/branch**, just the path to your packages like it would show in the filesystem.*
+
+The *path/to/packages* provided can contain metadata for one or more packages. Each package version **must** be on a separate folder, and it's up to you to decide if you want to publish one or multiple versions of your package.
+
+The structure of a repository with multiple containers packages and versions could look something like this:
+
+```sh
+$ tree path/to/packages
+path/to/packages
+├── artifacthub-repo.yml
+├── container1
+│ ├── 1.0.0
+│ │ ├── README.md
+│ │ └── artifacthub-pkg.yml
+│ └── 2.0.0
+│ ├── README.md
+│ └── artifacthub-pkg.yml
+└── container2
+ └── 1.0.0
+ ├── README.md
+ └── artifacthub-pkg.yml
+```
+
+This structure is flexible, and in some cases where you only have a package and a version it can be greatly simplified. In the case of a single package with a single version available at a time (the publisher doesn't want to make previous ones available, for example), the structure could look like this:
+
+```sh
+$ tree path/to/packages
+path/to/packages
+├── artifacthub-repo.yml
+└── recipe1
+ ├── README.md
+ └── artifacthub-pkg.yml
+```
+
+In the previous case, even the `package1` directory could be omitted. The reason is that both packages names and versions are read from the `artifacthub-pkg.yml` metadata file, so directories names are not used at all.
+
+Each package version **needs** an `artifacthub-pkg.yml` metadata file. Please see the file [spec](https://github.com/artifacthub/hub/blob/master/docs/metadata/artifacthub-pkg.yml) for more details. The [artifacthub-repo.yml](https://github.com/artifacthub/hub/blob/master/docs/metadata/artifacthub-repo.yml) repository metadata file shown above can be used to setup features like [Verified publisher](https://github.com/artifacthub/hub/blob/master/docs/repositories.md#verified-publisher) or [Ownership claim](https://github.com/artifacthub/hub/blob/master/docs/repositories.md#ownership-claim). This file must be located at `/path/to/packages`.
+
+The [Artifact Hub metadata file](https://github.com/artifacthub/hub/blob/master/docs/metadata/artifacthub-pkg.yml) allows defining containers images. Bootable containers packages are **required** to provide a container image named `bootc`. Packages can optionally provide an alternative location for the bootable container image by defining a second image named `bootc-alternative-location`. Artifact Hub will check if the images provided have been signed with `cosign` and will consider the package to be *signed* when **all** images are signed.
+
+Once you have added your repository, you are all set up. As you add new versions of your containers packages or new packages to your git repository, they'll be automatically indexed and listed in Artifact Hub.
diff --git a/docs/repositories.md b/docs/repositories.md
index 49234146ba..a92d8f8c14 100644
--- a/docs/repositories.md
+++ b/docs/repositories.md
@@ -6,6 +6,7 @@ The following repositories kinds are supported at the moment:
- [Argo templates repositories](https://github.com/artifacthub/hub/blob/master/docs/argo_templates_repositories.md)
- [Backstage plugins repositories](https://github.com/artifacthub/hub/blob/master/docs/backstage_plugins_repositories.md)
+- [Bootable containers repositories](https://github.com/artifacthub/hub/blob/master/docs/bootable_containers_repositories.md)
- [Containers images repositories](https://github.com/artifacthub/hub/blob/master/docs/container_images_repositories.md)
- [CoreDNS plugins repositories](https://github.com/artifacthub/hub/blob/master/docs/coredns_plugins_repositories.md)
- [Falco rules repositories](https://github.com/artifacthub/hub/blob/master/docs/falco_rules_repositories.md)
diff --git a/docs/www/headers/bootable_containers_repositories b/docs/www/headers/bootable_containers_repositories
new file mode 100644
index 0000000000..22ae3dcbb6
--- /dev/null
+++ b/docs/www/headers/bootable_containers_repositories
@@ -0,0 +1,6 @@
+---
+title: "Bootable containers"
+aliases: [
+ "/bootable_containers_repositories",
+]
+---
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index 44d02828a5..c554e9e8c1 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -265,7 +265,7 @@ func (h *Handlers) setupRouter() {
r.Get("/stats", h.Packages.GetStats)
r.With(corsMW).Get("/search", h.Packages.Search)
r.With(h.Users.RequireLogin).Get("/starred", h.Packages.GetStarredByUser)
- r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp|^inspektor-gadget|^tekton-stepaction|^meshery|^opencost|^radius$}/{repoName}/{packageName}", func(r chi.Router) {
+ r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp|^inspektor-gadget|^tekton-stepaction|^meshery|^opencost|^radius|^bootc$}/{repoName}/{packageName}", func(r chi.Router) {
r.Get("/feed/rss", h.Packages.RssFeed)
r.With(corsMW).Get("/summary", h.Packages.GetSummary)
r.Get("/{version}", h.Packages.Get)
@@ -430,7 +430,7 @@ func (h *Handlers) setupRouter() {
// Index special entry points
r.Route("/packages", func(r chi.Router) {
- r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp|^inspektor-gadget|^tekton-stepaction|^meshery|^opencost|^radius$}/{repoName}/{packageName}", func(r chi.Router) {
+ r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp|^inspektor-gadget|^tekton-stepaction|^meshery|^opencost|^radius|^bootc$}/{repoName}/{packageName}", func(r chi.Router) {
r.With(h.Packages.InjectIndexMeta).Get("/{version}", h.Static.Index)
r.With(h.Packages.InjectIndexMeta).Get("/", h.Static.Index)
})
diff --git a/internal/handlers/pkg/handlers_test.go b/internal/handlers/pkg/handlers_test.go
index 7ee138d922..c7f240ca87 100644
--- a/internal/handlers/pkg/handlers_test.go
+++ b/internal/handlers/pkg/handlers_test.go
@@ -2210,6 +2210,17 @@ func TestBuildURL(t *testing.T) {
"2.0.0",
baseURL + "/packages/radius/repo1/pkg1/2.0.0",
},
+ {
+ &hub.Package{
+ NormalizedName: "pkg1",
+ Repository: &hub.Repository{
+ Kind: hub.Bootc,
+ Name: "repo1",
+ },
+ },
+ "2.0.0",
+ baseURL + "/packages/bootc/repo1/pkg1/2.0.0",
+ },
}
for _, tc := range testCases {
t.Run(tc.expectedPkgURL, func(t *testing.T) {
diff --git a/internal/hub/repo.go b/internal/hub/repo.go
index 16b650229a..fbaa8d822d 100644
--- a/internal/hub/repo.go
+++ b/internal/hub/repo.go
@@ -127,6 +127,9 @@ const (
// Radius represents a repository with Radius recipes.
Radius RepositoryKind = 26
+
+ // Bootc represents a repository with Bootable containers.
+ Bootc RepositoryKind = 27
)
// GetKindName returns the name of the provided repository kind.
@@ -136,6 +139,8 @@ func GetKindName(kind RepositoryKind) string {
return "argo-template"
case Backstage:
return "backstage"
+ case Bootc:
+ return "bootc"
case Container:
return "container"
case CoreDNS:
@@ -199,6 +204,8 @@ func GetKindFromName(kind string) (RepositoryKind, error) {
return ArgoTemplate, nil
case "backstage":
return Backstage, nil
+ case "bootc":
+ return Bootc, nil
case "container":
return Container, nil
case "coredns":
diff --git a/internal/pkg/metadata.go b/internal/pkg/metadata.go
index d962ea5da9..52bbca865d 100644
--- a/internal/pkg/metadata.go
+++ b/internal/pkg/metadata.go
@@ -16,6 +16,14 @@ import (
)
const (
+ // bootcImage represents the name that must be used for the container image
+ // in a Bootable container package.
+ bootcImage = "bootc"
+
+ // bootcImageAlternativeLoc represents the name that must be used for the
+ // container image alternative location in a Bootable container package.
+ bootcImageAlternativeLoc = "bootc-alternative-location"
+
// gadgetImage represents the name that must be used for the gadget image
// in an Inspektor gadget package.
gadgetImage = "gadget"
@@ -255,6 +263,33 @@ func ValidateContainersImages(kind hub.RepositoryKind, images []*hub.ContainerIm
// Repository kind specific validation
switch kind {
+ case hub.Bootc:
+ // Bootable container image is required
+ if len(images) == 0 || (len(images) == 1 && images[0].Name != bootcImage) {
+ errs = multierror.Append(errs, fmt.Errorf(`"%s" image not provided`, bootcImage))
+ }
+
+ // A second container image pointing to an alternative location may be provided
+ if len(images) == 2 {
+ imagesNames := []string{images[0].Name, images[1].Name}
+ sort.Strings(imagesNames)
+ if imagesNames[0] != bootcImage || imagesNames[1] != bootcImageAlternativeLoc {
+ errs = multierror.Append(errs, fmt.Errorf(
+ `only "%s" and "%s" images can be provided`,
+ bootcImage,
+ bootcImageAlternativeLoc,
+ ))
+ }
+ }
+
+ // Providing more than two images is not allowed
+ if len(images) > 2 {
+ errs = multierror.Append(errs, fmt.Errorf(
+ `only "%s" and "%s" images can be provided`,
+ bootcImage,
+ bootcImageAlternativeLoc,
+ ))
+ }
case hub.InspektorGadget:
// Gadget image is required
if len(images) == 0 || (len(images) == 1 && images[0].Name != gadgetImage) {
diff --git a/internal/pkg/metadata_test.go b/internal/pkg/metadata_test.go
index bfa7e9671e..ce9536754e 100644
--- a/internal/pkg/metadata_test.go
+++ b/internal/pkg/metadata_test.go
@@ -610,6 +610,88 @@ func TestValidatePackageMetadata(t *testing.T) {
`only "gadget" and "gadget-alternative-location" images can be provided`,
},
},
+ {
+ hub.Bootc,
+ &hub.PackageMetadata{
+ Version: "1.0.0",
+ Name: "pkg1",
+ DisplayName: "Package 1",
+ CreatedAt: "2006-01-02T15:04:05Z",
+ Description: "description",
+ },
+ []string{
+ `"bootc" image not provided`,
+ },
+ },
+ {
+ hub.Bootc,
+ &hub.PackageMetadata{
+ Version: "1.0.0",
+ Name: "pkg1",
+ DisplayName: "Package 1",
+ CreatedAt: "2006-01-02T15:04:05Z",
+ Description: "description",
+ ContainersImages: []*hub.ContainerImage{
+ {
+ Name: "something",
+ Image: "registry.io/namespace/something:tag",
+ },
+ },
+ },
+ []string{
+ `"bootc" image not provided`,
+ },
+ },
+ {
+ hub.Bootc,
+ &hub.PackageMetadata{
+ Version: "1.0.0",
+ Name: "pkg1",
+ DisplayName: "Package 1",
+ CreatedAt: "2006-01-02T15:04:05Z",
+ Description: "description",
+ ContainersImages: []*hub.ContainerImage{
+ {
+ Name: "bootc",
+ Image: "registry.io/namespace/bootc:tag",
+ },
+ {
+ Name: "something",
+ Image: "registry.io/namespace/something:tag",
+ },
+ },
+ },
+ []string{
+ `only "bootc" and "bootc-alternative-location" images can be provided`,
+ },
+ },
+ {
+ hub.Bootc,
+ &hub.PackageMetadata{
+ Version: "1.0.0",
+ Name: "pkg1",
+ DisplayName: "Package 1",
+ CreatedAt: "2006-01-02T15:04:05Z",
+ Description: "description",
+ ContainersImages: []*hub.ContainerImage{
+ {
+ Name: "bootc",
+ Image: "registry.io/namespace/bootc:tag",
+ },
+ {
+ Name: "bootc-alternative-location",
+ Image: "registry2.io/namespace/bootc:tag",
+ },
+ {
+ Name: "something",
+ Image: "registry.io/namespace/something:tag",
+ },
+ },
+ },
+ []string{
+ `only "bootc" and "bootc-alternative-location" images can be provided`,
+ },
+ },
}
for i, tc := range testCases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
@@ -769,6 +851,65 @@ func TestValidatePackageMetadata(t *testing.T) {
},
},
},
+ {
+ hub.Bootc,
+ &hub.PackageMetadata{
+ Version: "1.0.0",
+ Name: "pkg1",
+ DisplayName: "Package 1",
+ CreatedAt: "2006-01-02T15:04:05Z",
+ Description: "description",
+ Category: "security",
+ ContainersImages: []*hub.ContainerImage{
+ {
+ Name: "bootc",
+ Image: "registry.io/namespace/bootc:tag",
+ },
+ },
+ },
+ },
+ {
+ hub.Bootc,
+ &hub.PackageMetadata{
+ Version: "1.0.0",
+ Name: "pkg1",
+ DisplayName: "Package 1",
+ CreatedAt: "2006-01-02T15:04:05Z",
+ Description: "description",
+ Category: "security",
+ ContainersImages: []*hub.ContainerImage{
+ {
+ Name: "bootc",
+ Image: "registry.io/namespace/bootc:tag",
+ },
+ {
+ Name: "bootc-alternative-location",
+ Image: "registry2.io/namespace/bootc:tag",
+ },
+ },
+ },
+ },
+ {
+ hub.Bootc,
+ &hub.PackageMetadata{
+ Version: "1.0.0",
+ Name: "pkg1",
+ DisplayName: "Package 1",
+ CreatedAt: "2006-01-02T15:04:05Z",
+ Description: "description",
+ Category: "security",
+ ContainersImages: []*hub.ContainerImage{
+ {
+ Name: "bootc-alternative-location",
+ Image: "registry2.io/namespace/bootc:tag",
+ },
+ {
+ Name: "bootc",
+ Image: "registry.io/namespace/bootc:tag",
+ },
+ },
+ },
+ },
}
for i, tc := range testCases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
diff --git a/internal/repo/manager.go b/internal/repo/manager.go
index e966430ca1..ebf0995963 100644
--- a/internal/repo/manager.go
+++ b/internal/repo/manager.go
@@ -81,6 +81,7 @@ var (
validRepositoryKinds = []hub.RepositoryKind{
hub.ArgoTemplate,
hub.Backstage,
+ hub.Bootc,
hub.Container,
hub.CoreDNS,
hub.Falco,
@@ -287,6 +288,7 @@ func (m *Manager) ClaimOwnership(ctx context.Context, repoName, orgName string)
case
hub.ArgoTemplate,
hub.Backstage,
+ hub.Bootc,
hub.CoreDNS,
hub.Falco,
hub.Gatekeeper,
@@ -471,6 +473,7 @@ func (m *Manager) locateMetadataFile(r *hub.Repository, basePath string) string
case
hub.ArgoTemplate,
hub.Backstage,
+ hub.Bootc,
hub.CoreDNS,
hub.Falco,
hub.Gatekeeper,
@@ -840,6 +843,7 @@ func (m *Manager) validateURL(r *hub.Repository) error {
case
hub.ArgoTemplate,
hub.Backstage,
+ hub.Bootc,
hub.CoreDNS,
hub.Falco,
hub.Gatekeeper,
diff --git a/internal/tracker/helpers.go b/internal/tracker/helpers.go
index bfd8b5865d..4926c7b4a8 100644
--- a/internal/tracker/helpers.go
+++ b/internal/tracker/helpers.go
@@ -115,6 +115,7 @@ func SetupSource(i *hub.TrackerSourceInput) hub.TrackerSource {
case
hub.ArgoTemplate,
hub.Backstage,
+ hub.Bootc,
hub.CoreDNS,
hub.Gatekeeper,
hub.Headlamp,
diff --git a/internal/tracker/source/generic/generic.go b/internal/tracker/source/generic/generic.go
index 1a8de2e691..3ce75cfec0 100644
--- a/internal/tracker/source/generic/generic.go
+++ b/internal/tracker/source/generic/generic.go
@@ -148,7 +148,7 @@ func (s *TrackerSource) GetPackagesAvailable() (map[string]*hub.Package, error)
// Check if the package is signed (for applicable kinds)
switch p.Repository.Kind {
- case hub.InspektorGadget, hub.Kubewarden:
+ case hub.Bootc, hub.InspektorGadget, hub.Kubewarden:
// We'll consider the package signed if all images are signed
signedImages := 0
for _, entry := range p.ContainersImages {
diff --git a/internal/tracker/tracker.go b/internal/tracker/tracker.go
index 80f2be7cac..06c7d21622 100644
--- a/internal/tracker/tracker.go
+++ b/internal/tracker/tracker.go
@@ -186,6 +186,7 @@ func (t *Tracker) cloneRepository() (string, string, error) {
case
hub.ArgoTemplate,
hub.Backstage,
+ hub.Bootc,
hub.CoreDNS,
hub.Falco,
hub.Gatekeeper,
diff --git a/scripts/prepare-docs.sh b/scripts/prepare-docs.sh
index 039f7742bc..7dce31a754 100755
--- a/scripts/prepare-docs.sh
+++ b/scripts/prepare-docs.sh
@@ -8,6 +8,7 @@ mkdir -p docs/www/content/topics/repositories
cat docs/www/headers/repositories docs/repositories.md > docs/www/content/topics/repositories/_index.md
cat docs/www/headers/argo_templates_repositories docs/argo_templates_repositories.md > docs/www/content/topics/repositories/argo-templates.md
cat docs/www/headers/backstage_plugins_repositories docs/backstage_plugins_repositories.md > docs/www/content/topics/repositories/backstage-plugins.md
+cat docs/www/headers/bootable_containers_repositories docs/bootable_containers_repositories.md > docs/www/content/topics/repositories/bootable-containers.md
cat docs/www/headers/container_images_repositories docs/container_images_repositories.md > docs/www/content/topics/repositories/container-images.md
cat docs/www/headers/coredns_plugins_repositories docs/coredns_plugins_repositories.md > docs/www/content/topics/repositories/coredns-plugins.md
cat docs/www/headers/falco_rules_repositories docs/falco_rules_repositories.md > docs/www/content/topics/repositories/falco-rules.md
diff --git a/web/public/static/media/bootc-light.svg b/web/public/static/media/bootc-light.svg
new file mode 100644
index 0000000000..0fb7245802
--- /dev/null
+++ b/web/public/static/media/bootc-light.svg
@@ -0,0 +1,14 @@
+
diff --git a/web/public/static/media/bootc.svg b/web/public/static/media/bootc.svg
new file mode 100644
index 0000000000..8a9817fbbe
--- /dev/null
+++ b/web/public/static/media/bootc.svg
@@ -0,0 +1,14 @@
+
diff --git a/web/public/static/media/bootc_icon.png b/web/public/static/media/bootc_icon.png
new file mode 100644
index 0000000000..09ce8bbd20
Binary files /dev/null and b/web/public/static/media/bootc_icon.png differ
diff --git a/web/public/static/media/placeholder_pkg_bootc.png b/web/public/static/media/placeholder_pkg_bootc.png
new file mode 100644
index 0000000000..f23c20aa66
Binary files /dev/null and b/web/public/static/media/placeholder_pkg_bootc.png differ
diff --git a/web/src/layout/common/Image.tsx b/web/src/layout/common/Image.tsx
index 305282f1b0..d8830adaee 100644
--- a/web/src/layout/common/Image.tsx
+++ b/web/src/layout/common/Image.tsx
@@ -81,6 +81,8 @@ const Image = (props: Props) => {
return '/static/media/placeholder_pkg_opencost.png';
case RepositoryKind.RadiusRecipe:
return '/static/media/placeholder_pkg_radius.png';
+ case RepositoryKind.Bootc:
+ return '/static/media/placeholder_pkg_bootc.png';
default:
return PLACEHOLDER_SRC;
}
diff --git a/web/src/layout/common/RepositoryIcon.tsx b/web/src/layout/common/RepositoryIcon.tsx
index e19cc2f0a2..398222db4e 100644
--- a/web/src/layout/common/RepositoryIcon.tsx
+++ b/web/src/layout/common/RepositoryIcon.tsx
@@ -117,6 +117,10 @@ const ICONS = {
default: '/static/media/radius.svg',
white: '/static/media/radius-light.svg',
},
+ [RepositoryKind.Bootc]: {
+ default: '/static/media/bootc.svg',
+ white: '/static/media/bootc-light.svg',
+ },
};
const RepositoryIcon = (props: Props) => {
diff --git a/web/src/layout/common/badges/Signed.tsx b/web/src/layout/common/badges/Signed.tsx
index 5ba8fb329f..26542e05b2 100644
--- a/web/src/layout/common/badges/Signed.tsx
+++ b/web/src/layout/common/badges/Signed.tsx
@@ -32,6 +32,7 @@ const Signed = (props: Props) => {
RepositoryKind.TektonPipeline,
RepositoryKind.TektonTask,
RepositoryKind.TektonStepAction,
+ RepositoryKind.Bootc,
].includes(props.repoKind);
return (
diff --git a/web/src/layout/controlPanel/repositories/Modal.tsx b/web/src/layout/controlPanel/repositories/Modal.tsx
index 5039095033..5d608c75db 100644
--- a/web/src/layout/controlPanel/repositories/Modal.tsx
+++ b/web/src/layout/controlPanel/repositories/Modal.tsx
@@ -548,6 +548,17 @@ const RepositoryModal = (props: Props) => {
);
break;
+ case RepositoryKind.Bootc:
+ link = (
+
{ RepositoryKind.MesheryDesign, RepositoryKind.OpenCost, RepositoryKind.RadiusRecipe, + RepositoryKind.Bootc, ].includes(selectedKind) && (