Add support for bootable container images (#4262)

Signed-off-by: Sergio Castaño Arteaga <tegioz@icloud.com>
Signed-off-by: Cintia Sánchez García <cynthiasg@icloud.com>
Co-authored-by: Sergio Castaño Arteaga <tegioz@icloud.com>
Co-authored-by: Cintia Sanchez Garcia <cynthiasg@icloud.com>
This commit is contained in:
Sergio Castaño Arteaga 2025-01-27 11:18:59 +01:00 committed by GitHub
parent 5a5a556006
commit ebfcc1cb55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 529 additions and 58 deletions

View File

@ -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/)

View File

@ -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

View File

@ -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"

View File

@ -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,

View File

@ -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;

View File

@ -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'
);

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -0,0 +1,6 @@
---
title: "Bootable containers"
aliases: [
"/bootable_containers_repositories",
]
---

View File

@ -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)
})

View File

@ -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) {

View File

@ -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":

View File

@ -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) {

View File

@ -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) {

View File

@ -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,

View File

@ -115,6 +115,7 @@ func SetupSource(i *hub.TrackerSourceInput) hub.TrackerSource {
case
hub.ArgoTemplate,
hub.Backstage,
hub.Bootc,
hub.CoreDNS,
hub.Gatekeeper,
hub.Headlamp,

View File

@ -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 {

View File

@ -186,6 +186,7 @@ func (t *Tracker) cloneRepository() (string, string, error) {
case
hub.ArgoTemplate,
hub.Backstage,
hub.Bootc,
hub.CoreDNS,
hub.Falco,
hub.Gatekeeper,

View File

@ -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

View File

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000" preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)" fill="#ffffff" stroke="none">
<path d="M3745 4884 c-268 -47 -454 -155 -624 -359 -171 -207 -245 -377 -411 -935 -43 -146 -83 -277 -89 -292 l-11 -28 -657 0 -658 0 -23 57 c-13 31 -37 136 -52 232 -49 296 -78 363 -175 414 -30 16 -58 21 -115 21 -64 0 -83 -4 -127 -28 -30 -16 -64 -46 -80 -69 -27 -38 -28 -47 -31 -170 l-4 -129 -31 6 c-94 17 -229 27 -277 22 -144 -17 -238 -115 -240 -250 0 -59 27 -112 75 -144 50 -32 169 -69 248 -77 37 -4 69 -10 71 -14 3 -4 -29 -64 -70 -133 -50 -85 -77 -143 -84 -178 -11 -60 -14 -1775 -3 -2287 l6 -323 2228 0 2228 0 3 1358 4 1357 32 100 c77 231 108 484 99 783 -6 191 -19 266 -76 421 -161 441 -481 663 -950 660 -69 0 -162 -7 -206 -15z m441 -63 c357 -73 597 -323 700 -729 46 -181 50 -502 9 -737 -34 -195 -165 -675 -211 -771 -37 -78 -148 -164 -213 -164 -62 0 -152 79 -172 152 -22 83 -12 105 161 353 123 176 144 211 135 225 -15 25 -39 1 -126 -129 -77 -115 -99 -140 -123 -145 -15 -3 -205 -6 -421 -6 l-393 0 -30 38 c-16 20 -70 98 -121 172 -96 141 -117 163 -127 135 -9 -24 2 -43 126 -220 137 -195 170 -252 170 -295 0 -129 -114 -233 -222 -201 -47 14 -116 67 -145 110 -31 46 -57 118 -117 326 -36 128 -56 180 -66 180 -23 0 -23 -30 0 -131 12 -52 20 -98 17 -101 -9 -8 -507 -17 -507 -9 0 3 16 39 36 78 74 146 120 280 258 743 133 449 223 639 387 821 119 132 203 193 343 248 207 83 431 102 652 57z m-3158 -905 c15 -8 35 -22 44 -33 25 -27 64 -177 93 -358 24 -149 31 -170 89 -302 59 -132 136 -279 172 -330 l16 -23 -213 1 c-118 0 -234 4 -258 7 l-45 7 -23 95 c-13 52 -33 115 -46 140 -34 70 -61 78 -278 90 -199 10 -218 14 -296 54 -70 35 -87 62 -81 130 5 61 38 113 92 147 28 18 44 20 176 16 82 -3 179 -12 223 -22 43 -9 80 -15 82 -13 2 2 -3 32 -10 68 -19 86 -19 223 -1 258 33 63 101 95 184 87 30 -3 66 -12 80 -19z m1800 -1748 c181 -75 317 -208 393 -387 27 -63 28 -72 29 -234 0 -159 -1 -171 -26 -230 -82 -195 -233 -340 -414 -398 -93 -30 -254 -37 -354 -14 -259 57 -458 270 -503 535 -48 285 98 565 362 696 115 57 150 63 315 60 119 -2 142 -5 198 -28z"/>
<path d="M3489 4536 c-33 -23 -69 -78 -69 -105 0 -25 38 -10 50 19 13 31 54 60 85 60 9 0 25 5 36 11 16 8 18 13 8 25 -18 22 -70 17 -110 -10z"/>
<path d="M4497 4523 c-31 -8 -13 -27 33 -35 46 -8 86 -38 101 -76 11 -28 33 -24 37 5 4 27 -43 82 -85 99 -33 14 -53 16 -86 7z"/>
<path d="M3525 4236 c-17 -7 -43 -28 -58 -45 -53 -64 -29 -179 45 -217 127 -66 254 62 192 192 -31 66 -116 99 -179 70z m128 -57 c16 -23 17 -30 7 -50 -17 -31 -29 -39 -62 -39 -17 0 -33 9 -42 22 -20 28 -20 48 0 76 22 31 70 26 97 -9z"/>
<path d="M4432 4220 c-93 -57 -96 -178 -7 -245 49 -38 101 -43 145 -13 46 31 80 83 80 122 0 50 -39 108 -90 134 -55 27 -85 28 -128 2z m71 -82 l21 -28 -21 -27 c-26 -36 -59 -41 -89 -12 -28 26 -31 55 -7 81 24 27 71 20 96 -14z"/>
<path d="M4012 4189 c-63 -12 -139 -57 -171 -101 -26 -35 -39 -71 -55 -149 -5 -23 -14 -29 -72 -43 -100 -25 -221 -92 -202 -111 3 -3 30 8 60 24 96 52 228 88 228 64 0 -5 -26 -21 -58 -38 -66 -34 -187 -145 -181 -164 3 -9 24 4 59 36 69 63 147 113 177 113 13 0 23 -3 23 -6 0 -3 -26 -32 -59 -63 -59 -57 -115 -149 -108 -179 2 -13 9 -8 23 17 32 57 107 153 136 175 l28 20 22 -21 c103 -94 285 -97 411 -7 26 19 51 34 55 34 16 0 121 -101 158 -152 38 -52 57 -53 31 -1 -25 48 -80 110 -129 148 -80 60 -54 75 47 26 33 -16 84 -47 114 -70 76 -57 87 -51 20 12 -36 34 -83 66 -132 88 -43 18 -77 38 -77 43 0 16 123 -2 196 -28 83 -30 102 -33 85 -12 -15 18 -89 45 -191 70 l-85 21 -7 45 c-4 25 -24 67 -44 97 -60 87 -188 135 -302 112z m174 -67 c73 -38 124 -113 124 -184 -1 -76 -71 -166 -147 -187 -62 -18 -159 -13 -201 8 -81 41 -122 105 -122 189 0 148 200 249 346 174z"/>
<path d="M4000 4070 c-39 -39 -37 -67 9 -114 42 -43 53 -79 25 -90 -32 -12 -55 -6 -64 19 -11 29 -25 32 -34 9 -7 -19 18 -64 37 -64 6 -1 57 -1 111 -2 92 -1 100 0 118 22 16 19 17 26 6 42 -15 23 -34 20 -30 -5 4 -21 -19 -31 -53 -23 -38 10 -32 45 16 97 32 35 39 48 34 69 -4 14 -7 26 -8 26 -50 37 -136 45 -167 14z m104 -36 c23 -9 20 -31 -5 -45 -37 -19 -89 18 -62 44 8 9 46 9 67 1z"/>
<path d="M2543 2091 c-18 -11 -35 -31 -38 -43 -7 -30 -10 -144 -7 -241 2 -72 4 -81 31 -108 55 -55 151 -33 171 40 5 20 10 96 10 168 0 131 0 133 -27 163 -37 41 -94 50 -140 21z"/>
<path d="M2185 1814 c-93 -100 -110 -333 -35 -493 38 -80 139 -182 231 -231 63 -35 66 -35 207 -38 l143 -4 75 36 c139 66 256 204 283 334 26 124 7 281 -44 362 -31 49 -51 60 -108 60 -38 0 -49 -5 -71 -31 -32 -37 -33 -69 -5 -161 63 -206 -57 -381 -261 -382 -106 0 -207 64 -251 159 -26 56 -25 168 1 235 28 72 26 111 -9 149 -25 27 -36 31 -80 31 -43 0 -56 -5 -76 -26z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000" preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)" fill="#9232a9" stroke="none">
<path d="M3745 4884 c-268 -47 -454 -155 -624 -359 -171 -207 -245 -377 -411 -935 -43 -146 -83 -277 -89 -292 l-11 -28 -657 0 -658 0 -23 57 c-13 31 -37 136 -52 232 -49 296 -78 363 -175 414 -30 16 -58 21 -115 21 -64 0 -83 -4 -127 -28 -30 -16 -64 -46 -80 -69 -27 -38 -28 -47 -31 -170 l-4 -129 -31 6 c-94 17 -229 27 -277 22 -144 -17 -238 -115 -240 -250 0 -59 27 -112 75 -144 50 -32 169 -69 248 -77 37 -4 69 -10 71 -14 3 -4 -29 -64 -70 -133 -50 -85 -77 -143 -84 -178 -11 -60 -14 -1775 -3 -2287 l6 -323 2228 0 2228 0 3 1358 4 1357 32 100 c77 231 108 484 99 783 -6 191 -19 266 -76 421 -161 441 -481 663 -950 660 -69 0 -162 -7 -206 -15z m441 -63 c357 -73 597 -323 700 -729 46 -181 50 -502 9 -737 -34 -195 -165 -675 -211 -771 -37 -78 -148 -164 -213 -164 -62 0 -152 79 -172 152 -22 83 -12 105 161 353 123 176 144 211 135 225 -15 25 -39 1 -126 -129 -77 -115 -99 -140 -123 -145 -15 -3 -205 -6 -421 -6 l-393 0 -30 38 c-16 20 -70 98 -121 172 -96 141 -117 163 -127 135 -9 -24 2 -43 126 -220 137 -195 170 -252 170 -295 0 -129 -114 -233 -222 -201 -47 14 -116 67 -145 110 -31 46 -57 118 -117 326 -36 128 -56 180 -66 180 -23 0 -23 -30 0 -131 12 -52 20 -98 17 -101 -9 -8 -507 -17 -507 -9 0 3 16 39 36 78 74 146 120 280 258 743 133 449 223 639 387 821 119 132 203 193 343 248 207 83 431 102 652 57z m-3158 -905 c15 -8 35 -22 44 -33 25 -27 64 -177 93 -358 24 -149 31 -170 89 -302 59 -132 136 -279 172 -330 l16 -23 -213 1 c-118 0 -234 4 -258 7 l-45 7 -23 95 c-13 52 -33 115 -46 140 -34 70 -61 78 -278 90 -199 10 -218 14 -296 54 -70 35 -87 62 -81 130 5 61 38 113 92 147 28 18 44 20 176 16 82 -3 179 -12 223 -22 43 -9 80 -15 82 -13 2 2 -3 32 -10 68 -19 86 -19 223 -1 258 33 63 101 95 184 87 30 -3 66 -12 80 -19z m1800 -1748 c181 -75 317 -208 393 -387 27 -63 28 -72 29 -234 0 -159 -1 -171 -26 -230 -82 -195 -233 -340 -414 -398 -93 -30 -254 -37 -354 -14 -259 57 -458 270 -503 535 -48 285 98 565 362 696 115 57 150 63 315 60 119 -2 142 -5 198 -28z"/>
<path d="M3489 4536 c-33 -23 -69 -78 -69 -105 0 -25 38 -10 50 19 13 31 54 60 85 60 9 0 25 5 36 11 16 8 18 13 8 25 -18 22 -70 17 -110 -10z"/>
<path d="M4497 4523 c-31 -8 -13 -27 33 -35 46 -8 86 -38 101 -76 11 -28 33 -24 37 5 4 27 -43 82 -85 99 -33 14 -53 16 -86 7z"/>
<path d="M3525 4236 c-17 -7 -43 -28 -58 -45 -53 -64 -29 -179 45 -217 127 -66 254 62 192 192 -31 66 -116 99 -179 70z m128 -57 c16 -23 17 -30 7 -50 -17 -31 -29 -39 -62 -39 -17 0 -33 9 -42 22 -20 28 -20 48 0 76 22 31 70 26 97 -9z"/>
<path d="M4432 4220 c-93 -57 -96 -178 -7 -245 49 -38 101 -43 145 -13 46 31 80 83 80 122 0 50 -39 108 -90 134 -55 27 -85 28 -128 2z m71 -82 l21 -28 -21 -27 c-26 -36 -59 -41 -89 -12 -28 26 -31 55 -7 81 24 27 71 20 96 -14z"/>
<path d="M4012 4189 c-63 -12 -139 -57 -171 -101 -26 -35 -39 -71 -55 -149 -5 -23 -14 -29 -72 -43 -100 -25 -221 -92 -202 -111 3 -3 30 8 60 24 96 52 228 88 228 64 0 -5 -26 -21 -58 -38 -66 -34 -187 -145 -181 -164 3 -9 24 4 59 36 69 63 147 113 177 113 13 0 23 -3 23 -6 0 -3 -26 -32 -59 -63 -59 -57 -115 -149 -108 -179 2 -13 9 -8 23 17 32 57 107 153 136 175 l28 20 22 -21 c103 -94 285 -97 411 -7 26 19 51 34 55 34 16 0 121 -101 158 -152 38 -52 57 -53 31 -1 -25 48 -80 110 -129 148 -80 60 -54 75 47 26 33 -16 84 -47 114 -70 76 -57 87 -51 20 12 -36 34 -83 66 -132 88 -43 18 -77 38 -77 43 0 16 123 -2 196 -28 83 -30 102 -33 85 -12 -15 18 -89 45 -191 70 l-85 21 -7 45 c-4 25 -24 67 -44 97 -60 87 -188 135 -302 112z m174 -67 c73 -38 124 -113 124 -184 -1 -76 -71 -166 -147 -187 -62 -18 -159 -13 -201 8 -81 41 -122 105 -122 189 0 148 200 249 346 174z"/>
<path d="M4000 4070 c-39 -39 -37 -67 9 -114 42 -43 53 -79 25 -90 -32 -12 -55 -6 -64 19 -11 29 -25 32 -34 9 -7 -19 18 -64 37 -64 6 -1 57 -1 111 -2 92 -1 100 0 118 22 16 19 17 26 6 42 -15 23 -34 20 -30 -5 4 -21 -19 -31 -53 -23 -38 10 -32 45 16 97 32 35 39 48 34 69 -4 14 -7 26 -8 26 -50 37 -136 45 -167 14z m104 -36 c23 -9 20 -31 -5 -45 -37 -19 -89 18 -62 44 8 9 46 9 67 1z"/>
<path d="M2543 2091 c-18 -11 -35 -31 -38 -43 -7 -30 -10 -144 -7 -241 2 -72 4 -81 31 -108 55 -55 151 -33 171 40 5 20 10 96 10 168 0 131 0 133 -27 163 -37 41 -94 50 -140 21z"/>
<path d="M2185 1814 c-93 -100 -110 -333 -35 -493 38 -80 139 -182 231 -231 63 -35 66 -35 207 -38 l143 -4 75 36 c139 66 256 204 283 334 26 124 7 281 -44 362 -31 49 -51 60 -108 60 -38 0 -49 -5 -71 -31 -32 -37 -33 -69 -5 -161 63 -206 -57 -381 -261 -382 -106 0 -207 64 -251 159 -26 56 -25 168 1 235 28 72 26 111 -9 149 -25 27 -36 31 -80 31 -43 0 -56 -5 -76 -26z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

View File

@ -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;
}

View File

@ -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) => {

View File

@ -32,6 +32,7 @@ const Signed = (props: Props) => {
RepositoryKind.TektonPipeline,
RepositoryKind.TektonTask,
RepositoryKind.TektonStepAction,
RepositoryKind.Bootc,
].includes(props.repoKind);
return (

View File

@ -548,6 +548,17 @@ const RepositoryModal = (props: Props) => {
</ExternalLink>
);
break;
case RepositoryKind.Bootc:
link = (
<ExternalLink
href="/docs/topics/repositories/bootable-containers"
className="text-primary fw-bold"
label="Open documentation"
>
Bootable containers
</ExternalLink>
);
break;
}
if (isUndefined(link)) return;
@ -582,6 +593,7 @@ const RepositoryModal = (props: Props) => {
case RepositoryKind.MesheryDesign:
case RepositoryKind.OpenCost:
case RepositoryKind.RadiusRecipe:
case RepositoryKind.Bootc:
return (
<>
<p
@ -980,6 +992,7 @@ const RepositoryModal = (props: Props) => {
RepositoryKind.MesheryDesign,
RepositoryKind.OpenCost,
RepositoryKind.RadiusRecipe,
RepositoryKind.Bootc,
].includes(selectedKind) && (
<div>
<InputField
@ -1134,6 +1147,7 @@ const RepositoryModal = (props: Props) => {
RepositoryKind.MesheryDesign,
RepositoryKind.OpenCost,
RepositoryKind.RadiusRecipe,
RepositoryKind.Bootc,
].includes(selectedKind) && (
<div className="mt-4 mb-3">
<div className="form-check form-switch ps-0">

View File

@ -69,6 +69,11 @@ exports[`Repository Modal - repositories section creates snapshot 1`] = `
>
Backstage plugins
</option>
<option
value="27"
>
Bootable containers
</option>
<option
value="12"
>

View File

@ -310,7 +310,7 @@ exports[`Home index creates snapshot 1`] = `
<div
class="text-center px-3 px-xs-0"
>
Artifact Hub is a web-based application that enables finding, installing, and publishing Cloud Native packages and configurations. For example, this could include Helm charts and plugins, Falco configurations, Open Policy Agent (OPA) and Gatekeeper policies, OLM operators, Tinkerbell actions, kubectl plugins, Tekton tasks, pipelines and stepactions, KEDA scalers, CoreDNS plugins, Keptn integrations, container images, Kubewarden policies, Kyverno policies, Knative client, Backstage plugins, Argo templates, KubeArmor policies, KCL modules, Headlamp plugins, Inspektor gadgets, Meshery designs, OpenCost plugins and Radius recipes.
Artifact Hub is a web-based application that enables finding, installing, and publishing Cloud Native packages and configurations. For example, this could include Helm charts and plugins, Falco configurations, Open Policy Agent (OPA) and Gatekeeper policies, OLM operators, Tinkerbell actions, kubectl plugins, Tekton tasks, pipelines and stepactions, KEDA scalers, CoreDNS plugins, Keptn integrations, container images, Kubewarden policies, Kyverno policies, Knative client, Backstage plugins, Argo templates, KubeArmor policies, KCL modules, Headlamp plugins, Inspektor gadgets, Meshery designs, OpenCost plugins, Radius recipes and Bootable Containers.
<div
class="py-0 py-lg-5"
>
@ -369,6 +369,32 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
<a
aria-label="Open Bootable containers web"
class="link col iconLink"
href="https://containers.github.io/bootable/"
rel="noopener noreferrer"
role="button"
tabindex="-1"
target="_blank"
>
<div
class="d-flex flex-column justify-content-between align-items-center h-100"
>
<img
alt="Icon"
class="aboutIcon"
src="/static/media/bootc-light.svg"
/>
<div
class="d-none d-sm-block text-light mt-2 legendIcon"
>
<small>
Bootable containers
</small>
</div>
</div>
</a>
<a
aria-label="Open Container Initiative site"
class="link col iconLink"
@ -421,6 +447,10 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
</div>
<div
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
>
<a
aria-label="Open Falco site"
class="link col iconLink"
@ -447,10 +477,6 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
</div>
<div
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
>
<a
aria-label="Open Headlamp site"
class="link col iconLink"
@ -557,6 +583,10 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
</div>
<div
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
>
<a
aria-label="Open KEDA site"
class="link col iconLink"
@ -583,10 +613,6 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
</div>
<div
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
>
<a
aria-label="Open Keptn site"
class="link col iconLink"
@ -691,6 +717,10 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
</div>
<div
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
>
<a
aria-label="Open Kubewarden site"
class="link col iconLink"
@ -717,10 +747,6 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
</div>
<div
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
>
<a
aria-label="Open Kubewarden site"
class="link col iconLink"
@ -825,6 +851,10 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
</div>
<div
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
>
<a
aria-label="Open Policy Agent site"
class="link col iconLink"
@ -851,10 +881,6 @@ exports[`Home index creates snapshot 1`] = `
</div>
</div>
</a>
</div>
<div
class="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around"
>
<a
aria-label="Radius site"
class="link col iconLink"

View File

@ -127,7 +127,7 @@ describe('Home index', () => {
await waitFor(() => expect(API.getStats).toHaveBeenCalledTimes(1));
const links = await screen.findAllByRole('button');
expect(links).toHaveLength(30);
expect(links).toHaveLength(31);
expect(links[2]).toHaveProperty('href', 'https://github.com/artifacthub/hub');
expect(links[3]).toHaveProperty('href', 'https://cloud-native.slack.com/channels/artifact-hub');
@ -139,29 +139,30 @@ describe('Home index', () => {
// Packages
expect(links[6]).toHaveProperty('href', 'https://argoproj.github.io/argo-workflows/');
expect(links[7]).toHaveProperty('href', 'https://backstage.io/plugins');
expect(links[8]).toHaveProperty('href', 'https://opencontainers.org/');
expect(links[9]).toHaveProperty('href', 'https://coredns.io/');
expect(links[10]).toHaveProperty('href', 'https://falco.org/');
expect(links[11]).toHaveProperty('href', 'https://headlamp.dev/');
expect(links[12]).toHaveProperty('href', 'https://helm.sh/');
expect(links[13]).toHaveProperty('href', 'https://www.inspektor-gadget.io/');
expect(links[14]).toHaveProperty('href', 'https://kcl-lang.io/');
expect(links[15]).toHaveProperty('href', 'https://keda.sh/');
expect(links[16]).toHaveProperty('href', 'https://keptn.sh/');
expect(links[17]).toHaveProperty('href', 'https://github.com/knative/client');
expect(links[18]).toHaveProperty('href', 'https://krew.sigs.k8s.io/');
expect(links[19]).toHaveProperty('href', 'https://kubearmor.io/');
expect(links[20]).toHaveProperty('href', 'https://www.kubewarden.io/');
expect(links[21]).toHaveProperty('href', 'https://www.kyverno.io/');
expect(links[22]).toHaveProperty('href', 'https://meshery.io/');
expect(links[23]).toHaveProperty('href', 'https://github.com/operator-framework');
expect(links[24]).toHaveProperty('href', 'https://www.openpolicyagent.org/');
expect(links[25]).toHaveProperty('href', 'https://www.opencost.io/');
expect(links[26]).toHaveProperty('href', 'https://radapp.io/');
expect(links[27]).toHaveProperty('href', 'https://tekton.dev/');
expect(links[28]).toHaveProperty('href', 'https://tinkerbell.org/');
expect(links[8]).toHaveProperty('href', 'https://containers.github.io/bootable/');
expect(links[9]).toHaveProperty('href', 'https://opencontainers.org/');
expect(links[10]).toHaveProperty('href', 'https://coredns.io/');
expect(links[11]).toHaveProperty('href', 'https://falco.org/');
expect(links[12]).toHaveProperty('href', 'https://headlamp.dev/');
expect(links[13]).toHaveProperty('href', 'https://helm.sh/');
expect(links[14]).toHaveProperty('href', 'https://www.inspektor-gadget.io/');
expect(links[15]).toHaveProperty('href', 'https://kcl-lang.io/');
expect(links[16]).toHaveProperty('href', 'https://keda.sh/');
expect(links[17]).toHaveProperty('href', 'https://keptn.sh/');
expect(links[18]).toHaveProperty('href', 'https://github.com/knative/client');
expect(links[19]).toHaveProperty('href', 'https://krew.sigs.k8s.io/');
expect(links[20]).toHaveProperty('href', 'https://kubearmor.io/');
expect(links[21]).toHaveProperty('href', 'https://www.kubewarden.io/');
expect(links[22]).toHaveProperty('href', 'https://www.kyverno.io/');
expect(links[23]).toHaveProperty('href', 'https://meshery.io/');
expect(links[24]).toHaveProperty('href', 'https://github.com/operator-framework');
expect(links[25]).toHaveProperty('href', 'https://www.openpolicyagent.org/');
expect(links[26]).toHaveProperty('href', 'https://www.opencost.io/');
expect(links[27]).toHaveProperty('href', 'https://radapp.io/');
expect(links[28]).toHaveProperty('href', 'https://tekton.dev/');
expect(links[29]).toHaveProperty('href', 'https://tinkerbell.org/');
expect(links[29]).toHaveProperty('href', 'https://www.cncf.io/projects/');
expect(links[30]).toHaveProperty('href', 'https://www.cncf.io/projects/');
});
});
});

View File

@ -233,7 +233,7 @@ const HomeView = () => {
kubectl plugins, Tekton tasks, pipelines and stepactions, KEDA scalers, CoreDNS plugins, Keptn
integrations, container images, Kubewarden policies, Kyverno policies, Knative client, Backstage
plugins, Argo templates, KubeArmor policies, KCL modules, Headlamp plugins, Inspektor gadgets, Meshery
designs, OpenCost plugins and Radius recipes.
designs, OpenCost plugins, Radius recipes and Bootable Containers.
<div className="py-0 py-lg-5">
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink
@ -260,6 +260,18 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
<ExternalLink
href="https://containers.github.io/bootable/"
className={`col ${styles.iconLink}`}
label="Open Bootable containers web"
>
<div className="d-flex flex-column justify-content-between align-items-center h-100">
<RepositoryIcon kind={RepositoryKind.Bootc} type="white" className={styles.aboutIcon} />
<div className={`d-none d-sm-block text-light mt-2 ${styles.legendIcon}`}>
<small>Bootable containers</small>
</div>
</div>
</ExternalLink>
<ExternalLink
href="https://opencontainers.org"
className={`col ${styles.iconLink}`}
@ -284,6 +296,8 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
</div>
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink href="https://falco.org" className={`col ${styles.iconLink}`} label="Open Falco site">
<div className="d-flex flex-column justify-content-between align-items-center h-100">
<RepositoryIcon kind={RepositoryKind.Falco} type="white" className={styles.aboutIcon} />
@ -292,8 +306,6 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
</div>
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink
href="https://headlamp.dev"
className={`col ${styles.iconLink}`}
@ -338,6 +350,8 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
</div>
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink href="https://keda.sh" className={`col ${styles.iconLink}`} label="Open KEDA site">
<div className="d-flex flex-column justify-content-between align-items-center h-100">
<RepositoryIcon kind={RepositoryKind.KedaScaler} type="white" className={styles.aboutIcon} />
@ -346,8 +360,6 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
</div>
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink href="https://keptn.sh" className={`col ${styles.iconLink}`} label="Open Keptn site">
<div className="d-flex flex-column justify-content-between align-items-center h-100">
<RepositoryIcon kind={RepositoryKind.Keptn} type="white" className={styles.aboutIcon} />
@ -396,6 +408,8 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
</div>
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink
href="https://www.kubewarden.io"
className={`col ${styles.iconLink}`}
@ -408,8 +422,6 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
</div>
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink
href="https://www.kyverno.io"
className={`col ${styles.iconLink}`}
@ -458,6 +470,8 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
</div>
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink
href="https://www.opencost.io"
className={`col ${styles.iconLink}`}
@ -470,8 +484,6 @@ const HomeView = () => {
</div>
</div>
</ExternalLink>
</div>
<div className="mx-0 mx-md-3 mx-lg-5 my-4 my-sm-5 d-flex flex-row align-items-stretch justify-content-around">
<ExternalLink href="https://radapp.io" className={`col ${styles.iconLink}`} label="Radius site">
<div className="d-flex flex-column justify-content-between align-items-center h-100">
<RepositoryIcon kind={RepositoryKind.RadiusRecipe} type="white" className={styles.aboutIcon} />

View File

@ -176,6 +176,7 @@ const Details = (props: Props) => {
case RepositoryKind.MesheryDesign:
case RepositoryKind.OpenCost:
case RepositoryKind.RadiusRecipe:
case RepositoryKind.Bootc:
return (
<>
{props.package.appVersion && (

View File

@ -14,7 +14,7 @@ interface Props {
}
export const URL_regex =
/^https:\/\/([^\/?]+)\/packages\/(helm|falco|opa|olm|tbaction|krew|helm-plugin|tekton-task|keda-scaler|coredns|keptn|tekton-pipeline|kubewarden|gatekeeper|kyverno|knative-client-plugin|backstage|argo-template|kubearmor|inspektor-gadget|tekton-stepaction|meshery|opencost|radius|container)\/([a-z0-9-]+)\/([a-z0-9-]+)$/; // eslint-disable-line
/^https:\/\/([^\/?]+)\/packages\/(helm|falco|opa|olm|tbaction|krew|helm-plugin|tekton-task|keda-scaler|coredns|keptn|tekton-pipeline|kubewarden|gatekeeper|kyverno|knative-client-plugin|backstage|argo-template|kubearmor|inspektor-gadget|tekton-stepaction|meshery|opencost|radius|bootc|container)\/([a-z0-9-]+)\/([a-z0-9-]+)$/; // eslint-disable-line
const prepareRecommendations = (recommendations?: Recommendation[]): RecommendedPackage[] => {
const list: RecommendedPackage[] = [];

View File

@ -28,6 +28,7 @@ export enum RepositoryKind {
MesheryDesign,
OpenCost,
RadiusRecipe,
Bootc,
}
export enum PackageCategory {

View File

@ -105,6 +105,15 @@ export const REPOSITORY_KINDS: RepoKindDef[] = [
icon: <RepositoryIcon kind={RepositoryKind.Backstage} className="mw-100 mh-100" />,
active: true,
},
{
kind: RepositoryKind.Bootc,
label: 'bootc',
name: 'Bootable containers',
singular: 'Bootable container',
plural: 'Bootable containers',
icon: <RepositoryIcon kind={RepositoryKind.Bootc} className="mw-100 mh-100" />,
active: true,
},
{
kind: RepositoryKind.Container,
label: 'container',
@ -831,7 +840,7 @@ export const CVSS_V3_VECTORS: { [key: string]: CVSSVectorMetric[] } = {
export const OCI_PREFIX = 'oci://';
export const PKG_DETAIL_PATH =
/^\/packages\/(helm|falco|opa|olm|tbaction|krew|helm-plugin|tekton-task|keda-scaler|coredns|keptn|tekton-pipeline|kubewarden|gatekeeper|kyverno|knative-client-plugin|backstage|argo-template|kubearmor|kcl|headlamp|inspektor-gadget|tekton-stepaction|meshery|opencost|radius|container)\//;
/^\/packages\/(helm|falco|opa|olm|tbaction|krew|helm-plugin|tekton-task|keda-scaler|coredns|keptn|tekton-pipeline|kubewarden|gatekeeper|kyverno|knative-client-plugin|backstage|argo-template|kubearmor|kcl|headlamp|inspektor-gadget|tekton-stepaction|meshery|opencost|radius|bootc|container)\//;
export const HOME_ROUTES = [
'/verify-email',

View File

@ -117,6 +117,7 @@ const getInstallMethods = (props: PackageInfo): InstallMethodOutput => {
case RepositoryKind.MesheryDesign:
case RepositoryKind.OpenCost:
case RepositoryKind.RadiusRecipe:
case RepositoryKind.Bootc:
if (isUndefined(pkg.install)) {
output.errorMessage = 'This package does not include installation instructions yet.';
hasError = true;

View File

@ -56,6 +56,8 @@ const getRepoKind = (repoName: string): RepositoryKind | null => {
return RepositoryKind.OpenCost;
case 'radius':
return RepositoryKind.RadiusRecipe;
case 'bootc':
return RepositoryKind.Bootc;
default:
return null;
}
@ -117,6 +119,8 @@ const getRepoKindName = (repoKind: RepositoryKind): string | null => {
return 'opencost';
case RepositoryKind.RadiusRecipe:
return 'radius';
case RepositoryKind.Bootc:
return 'bootc';
default:
return null;
}

View File

@ -103,6 +103,8 @@ const getRepoKindName = (repoKind: RepositoryKind): string | null => {
return 'opencost';
case RepositoryKind.RadiusRecipe:
return 'radius';
case RepositoryKind.Bootc:
return 'bootc';
default:
return null;
}

View File

@ -82,6 +82,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;
}

View File

@ -39,6 +39,7 @@ const ICONS: IconsList = {
[RepositoryKind.MesheryDesign]: <SVGIcons name="meshery" />,
[RepositoryKind.OpenCost]: <SVGIcons name="opencost" />,
[RepositoryKind.RadiusRecipe]: <SVGIcons name="radius" />,
[RepositoryKind.Bootc]: <SVGIcons name="bootc" />,
};
const RepositoryIcon = (props: Props) => (

View File

@ -124,6 +124,10 @@ const REPOSITORY_KINDS: RepoKindDef[] = [
kind: RepositoryKind.RadiusRecipe,
name: 'Radius recipe',
},
{
kind: RepositoryKind.Bootc,
name: 'Bootable container',
},
];
const Wrapper = styled('span')`

View File

@ -1289,6 +1289,30 @@ const SVGIcons = (props: Props) => (
</svg>
);
case 'bootc':
return (
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.0"
width="512.000000pt"
height="512.000000pt"
viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet"
>
<title>{props.name}</title>
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)" fill="#9232a9" stroke="none">
<path d="M3745 4884 c-268 -47 -454 -155 -624 -359 -171 -207 -245 -377 -411 -935 -43 -146 -83 -277 -89 -292 l-11 -28 -657 0 -658 0 -23 57 c-13 31 -37 136 -52 232 -49 296 -78 363 -175 414 -30 16 -58 21 -115 21 -64 0 -83 -4 -127 -28 -30 -16 -64 -46 -80 -69 -27 -38 -28 -47 -31 -170 l-4 -129 -31 6 c-94 17 -229 27 -277 22 -144 -17 -238 -115 -240 -250 0 -59 27 -112 75 -144 50 -32 169 -69 248 -77 37 -4 69 -10 71 -14 3 -4 -29 -64 -70 -133 -50 -85 -77 -143 -84 -178 -11 -60 -14 -1775 -3 -2287 l6 -323 2228 0 2228 0 3 1358 4 1357 32 100 c77 231 108 484 99 783 -6 191 -19 266 -76 421 -161 441 -481 663 -950 660 -69 0 -162 -7 -206 -15z m441 -63 c357 -73 597 -323 700 -729 46 -181 50 -502 9 -737 -34 -195 -165 -675 -211 -771 -37 -78 -148 -164 -213 -164 -62 0 -152 79 -172 152 -22 83 -12 105 161 353 123 176 144 211 135 225 -15 25 -39 1 -126 -129 -77 -115 -99 -140 -123 -145 -15 -3 -205 -6 -421 -6 l-393 0 -30 38 c-16 20 -70 98 -121 172 -96 141 -117 163 -127 135 -9 -24 2 -43 126 -220 137 -195 170 -252 170 -295 0 -129 -114 -233 -222 -201 -47 14 -116 67 -145 110 -31 46 -57 118 -117 326 -36 128 -56 180 -66 180 -23 0 -23 -30 0 -131 12 -52 20 -98 17 -101 -9 -8 -507 -17 -507 -9 0 3 16 39 36 78 74 146 120 280 258 743 133 449 223 639 387 821 119 132 203 193 343 248 207 83 431 102 652 57z m-3158 -905 c15 -8 35 -22 44 -33 25 -27 64 -177 93 -358 24 -149 31 -170 89 -302 59 -132 136 -279 172 -330 l16 -23 -213 1 c-118 0 -234 4 -258 7 l-45 7 -23 95 c-13 52 -33 115 -46 140 -34 70 -61 78 -278 90 -199 10 -218 14 -296 54 -70 35 -87 62 -81 130 5 61 38 113 92 147 28 18 44 20 176 16 82 -3 179 -12 223 -22 43 -9 80 -15 82 -13 2 2 -3 32 -10 68 -19 86 -19 223 -1 258 33 63 101 95 184 87 30 -3 66 -12 80 -19z m1800 -1748 c181 -75 317 -208 393 -387 27 -63 28 -72 29 -234 0 -159 -1 -171 -26 -230 -82 -195 -233 -340 -414 -398 -93 -30 -254 -37 -354 -14 -259 57 -458 270 -503 535 -48 285 98 565 362 696 115 57 150 63 315 60 119 -2 142 -5 198 -28z" />
<path d="M3489 4536 c-33 -23 -69 -78 -69 -105 0 -25 38 -10 50 19 13 31 54 60 85 60 9 0 25 5 36 11 16 8 18 13 8 25 -18 22 -70 17 -110 -10z" />
<path d="M4497 4523 c-31 -8 -13 -27 33 -35 46 -8 86 -38 101 -76 11 -28 33 -24 37 5 4 27 -43 82 -85 99 -33 14 -53 16 -86 7z" />
<path d="M3525 4236 c-17 -7 -43 -28 -58 -45 -53 -64 -29 -179 45 -217 127 -66 254 62 192 192 -31 66 -116 99 -179 70z m128 -57 c16 -23 17 -30 7 -50 -17 -31 -29 -39 -62 -39 -17 0 -33 9 -42 22 -20 28 -20 48 0 76 22 31 70 26 97 -9z" />
<path d="M4432 4220 c-93 -57 -96 -178 -7 -245 49 -38 101 -43 145 -13 46 31 80 83 80 122 0 50 -39 108 -90 134 -55 27 -85 28 -128 2z m71 -82 l21 -28 -21 -27 c-26 -36 -59 -41 -89 -12 -28 26 -31 55 -7 81 24 27 71 20 96 -14z" />
<path d="M4012 4189 c-63 -12 -139 -57 -171 -101 -26 -35 -39 -71 -55 -149 -5 -23 -14 -29 -72 -43 -100 -25 -221 -92 -202 -111 3 -3 30 8 60 24 96 52 228 88 228 64 0 -5 -26 -21 -58 -38 -66 -34 -187 -145 -181 -164 3 -9 24 4 59 36 69 63 147 113 177 113 13 0 23 -3 23 -6 0 -3 -26 -32 -59 -63 -59 -57 -115 -149 -108 -179 2 -13 9 -8 23 17 32 57 107 153 136 175 l28 20 22 -21 c103 -94 285 -97 411 -7 26 19 51 34 55 34 16 0 121 -101 158 -152 38 -52 57 -53 31 -1 -25 48 -80 110 -129 148 -80 60 -54 75 47 26 33 -16 84 -47 114 -70 76 -57 87 -51 20 12 -36 34 -83 66 -132 88 -43 18 -77 38 -77 43 0 16 123 -2 196 -28 83 -30 102 -33 85 -12 -15 18 -89 45 -191 70 l-85 21 -7 45 c-4 25 -24 67 -44 97 -60 87 -188 135 -302 112z m174 -67 c73 -38 124 -113 124 -184 -1 -76 -71 -166 -147 -187 -62 -18 -159 -13 -201 8 -81 41 -122 105 -122 189 0 148 200 249 346 174z" />
<path d="M4000 4070 c-39 -39 -37 -67 9 -114 42 -43 53 -79 25 -90 -32 -12 -55 -6 -64 19 -11 29 -25 32 -34 9 -7 -19 18 -64 37 -64 6 -1 57 -1 111 -2 92 -1 100 0 118 22 16 19 17 26 6 42 -15 23 -34 20 -30 -5 4 -21 -19 -31 -53 -23 -38 10 -32 45 16 97 32 35 39 48 34 69 -4 14 -7 26 -8 26 -50 37 -136 45 -167 14z m104 -36 c23 -9 20 -31 -5 -45 -37 -19 -89 18 -62 44 8 9 46 9 67 1z" />
<path d="M2543 2091 c-18 -11 -35 -31 -38 -43 -7 -30 -10 -144 -7 -241 2 -72 4 -81 31 -108 55 -55 151 -33 171 40 5 20 10 96 10 168 0 131 0 133 -27 163 -37 41 -94 50 -140 21z" />
<path d="M2185 1814 c-93 -100 -110 -333 -35 -493 38 -80 139 -182 231 -231 63 -35 66 -35 207 -38 l143 -4 75 36 c139 66 256 204 283 334 26 124 7 281 -44 362 -31 49 -51 60 -108 60 -38 0 -49 -5 -71 -31 -32 -37 -33 -69 -5 -161 63 -206 -57 -381 -261 -382 -106 0 -207 64 -251 159 -26 56 -25 168 1 235 28 72 26 111 -9 149 -25 27 -36 31 -80 31 -43 0 -56 -5 -76 -26z" />
</g>
</svg>
);
default:
return null;
}

View File

@ -55,6 +55,7 @@ export enum RepositoryKind {
MesheryDesign,
OpenCost,
RadiusRecipe,
Bootc,
}
export interface SearchResults {