Skip to content

Commit

Permalink
Npm/config (#653)
Browse files Browse the repository at this point in the history
## Description

<!-- 
Please do not leave this blank 
This PR [adds/removes/fixes/replaces] the [feature/bug/etc]. 
-->

Please include a summary of the changes and the related issue. Please
also include relevant motivation and context. List any dependencies that
are required for this change.


## What type of PR is this? (check all applicable)

- [x] 🍕 Feature
- [x] 🐛 Bug Fix
- [x] 📝 Documentation Update
- [ ] 🎨 Style
- [ ] 🧑‍💻 Code Refactor
- [ ] 🔥 Performance Improvements
- [x] ✅ Test
- [ ] 🤖 Build
- [ ] 🔁 CI
- [ ] 📦 Chore (Release)
- [ ] ⏩ Revert

## Related Tickets & Documents

<!-- 
Please use this format link issue numbers: Fixes #123

https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword
-->
- Related Issue #633

## Added tests?

- [x] 👍 yes
- [ ] 🙅 no, because they aren't needed
- [ ] 🙋 no, because I need help
- [ ] Separate ticket for tests # (issue/pr)

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration


## Added to documentation?

- [ ] 📜 README.md
- [ ] 🙅 no documentation needed

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Uwe Krueger <[email protected]>
  • Loading branch information
hilmarf and mandelsoft authored Feb 22, 2024
1 parent b60bac1 commit 137c796
Show file tree
Hide file tree
Showing 30 changed files with 667 additions and 99 deletions.
5 changes: 4 additions & 1 deletion docs/reference/ocm.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ location a default configuration is composed according to known type specific
configuration files.

The following configuration sources are used:
- The docker configuration file at <code>~/.docker/config.jaon</code> is
- The docker configuration file at <code>~/.docker/config.json</code> is
read to feed in the configured credentials for OCI registries.

- The npm configuration file at <code>~/.npmrc</code> is
read to feed in the configured credentials for NPM registries.



With the option <code>--cred</code> it is possible to specify arbitrary credentials
Expand Down
28 changes: 28 additions & 0 deletions docs/reference/ocm_credential-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,19 @@ The following credential consumer types are used/supported:
- <code>certificateAuthority</code>: the certificate authority certificate used to verify certificates


- <code>Registry.npmjs.com</code>: NPM repository

It matches the <code>Registry.npmjs.com</code> consumer type and additionally acts like
the <code>hostpath</code> type.

Credential consumers of the consumer type Registry.npmjs.com evaluate the following credential properties:

- <code>username</code>: the basic auth user name
- <code>password</code>: the basic auth password
- <code>email</code>: NPM registry, require an email address
- <code>token</code>: the token attribute. May exist after login at any npm registry. Check your .npmrc file!


- <code>S3</code>: S3 credential matcher

This matcher is a hostpath matcher.
Expand Down Expand Up @@ -306,6 +319,21 @@ behaviours are described in the following list:
is read.


- Credential provider <code>NPMConfig</code>

This repository type can be used to access credentials stored in a file
following the NPM npmrc format (~/.npmrc). It take into account the
credentials helper section, also. If enabled, the described
credentials will be automatically assigned to appropriate consumer ids.

The following versions are supported:
- Version <code>v1</code>

The repository specification supports the following fields:
- <code>npmrcFile</code>: *string*: the file path to a NPM npmrc file
- <code>propagateConsumerIdentity</code>: *bool*(optional): enable consumer id propagation



### SEE ALSO

Expand Down
13 changes: 13 additions & 0 deletions docs/reference/ocm_get_credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ Matchers exist for the following usage contexts or consumer types:
- <code>certificateAuthority</code>: the certificate authority certificate used to verify certificates


- <code>Registry.npmjs.com</code>: NPM repository

It matches the <code>Registry.npmjs.com</code> consumer type and additionally acts like
the <code>hostpath</code> type.

Credential consumers of the consumer type Registry.npmjs.com evaluate the following credential properties:

- <code>username</code>: the basic auth user name
- <code>password</code>: the basic auth password
- <code>email</code>: NPM registry, require an email address
- <code>token</code>: the token attribute. May exist after login at any npm registry. Check your .npmrc file!


- <code>S3</code>: S3 credential matcher

This matcher is a hostpath matcher.
Expand Down
1 change: 1 addition & 0 deletions docs/reference/ocm_logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The following *tags* are used by the command line tool:

The following *realms* are used by the command line tool:
- <code>ocm</code>: general realm used for the ocm go library.
- <code>ocm/NPM</code>: NPM registry
- <code>ocm/accessmethod/ociartifact</code>: access method ociArtifact
- <code>ocm/compdesc</code>: component descriptor handling
- <code>ocm/config</code>: configuration management
Expand Down
17 changes: 13 additions & 4 deletions docs/reference/ocm_ocm-uploadhandlers.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ resource blob), it is possible to pass a target configuration controlling the
exact behaviour of the handler for selected artifacts.

The following handler names are possible:
- <code>plugin</code>: [downloaders provided by plugins]

sub namespace of the form <code>&lt;plugin name>/&lt;handler></code>

- <code>ocm/ociArtifacts</code>: downloading OCI artifacts

The <code>ociArtifacts</code> downloader is able to download OCI artifacts
Expand All @@ -64,6 +60,19 @@ The following handler names are possible:
Alternatively, a single string value can be given representing an OCI repository
reference.

- <code>plugin</code>: [downloaders provided by plugins]

sub namespace of the form <code>&lt;plugin name>/&lt;handler></code>

- <code>ocm/npmPackage</code>: uploading npm artifacts

The <code>ocm/npmPackage</code> uploader is able to upload npm artifacts
as artifact archive according to the npm package spec.
If registered the default mime type is: application/x-tgz

It accepts a plain string for the URL or a config with the following field:
'url': the URL of the npm repository.



See [ocm ocm-uploadhandlers](ocm_ocm-uploadhandlers.md) for further details on using
Expand Down
17 changes: 13 additions & 4 deletions docs/reference/ocm_transfer_commontransportarchive.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,6 @@ are configured for the operation. It has the following format
</center>

The uploader name may be a path expression with the following possibilities:
- <code>plugin</code>: [downloaders provided by plugins]

sub namespace of the form <code>&lt;plugin name>/&lt;handler></code>

- <code>ocm/ociArtifacts</code>: downloading OCI artifacts

The <code>ociArtifacts</code> downloader is able to download OCI artifacts
Expand All @@ -138,6 +134,19 @@ The uploader name may be a path expression with the following possibilities:
Alternatively, a single string value can be given representing an OCI repository
reference.

- <code>plugin</code>: [downloaders provided by plugins]

sub namespace of the form <code>&lt;plugin name>/&lt;handler></code>

- <code>ocm/npmPackage</code>: uploading npm artifacts

The <code>ocm/npmPackage</code> uploader is able to upload npm artifacts
as artifact archive according to the npm package spec.
If registered the default mime type is: application/x-tgz

It accepts a plain string for the URL or a config with the following field:
'url': the URL of the npm repository.



See [ocm ocm-uploadhandlers](ocm_ocm-uploadhandlers.md) for further details on using
Expand Down
17 changes: 13 additions & 4 deletions docs/reference/ocm_transfer_componentversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,6 @@ are configured for the operation. It has the following format
</center>

The uploader name may be a path expression with the following possibilities:
- <code>plugin</code>: [downloaders provided by plugins]

sub namespace of the form <code>&lt;plugin name>/&lt;handler></code>

- <code>ocm/ociArtifacts</code>: downloading OCI artifacts

The <code>ociArtifacts</code> downloader is able to download OCI artifacts
Expand All @@ -195,6 +191,19 @@ The uploader name may be a path expression with the following possibilities:
Alternatively, a single string value can be given representing an OCI repository
reference.

- <code>plugin</code>: [downloaders provided by plugins]

sub namespace of the form <code>&lt;plugin name>/&lt;handler></code>

- <code>ocm/npmPackage</code>: uploading npm artifacts

The <code>ocm/npmPackage</code> uploader is able to upload npm artifacts
as artifact archive according to the npm package spec.
If registered the default mime type is: application/x-tgz

It accepts a plain string for the URL or a config with the following field:
'url': the URL of the npm repository.



See [ocm ocm-uploadhandlers](ocm_ocm-uploadhandlers.md) for further details on using
Expand Down
6 changes: 1 addition & 5 deletions pkg/contexts/config/configutils/configure.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package configutils

import (
Expand All @@ -27,7 +23,7 @@ func Configure(path string) error {
func ConfigureContext(ctxp config.ContextProvider, path string) error {
ctx := config.FromProvider(ctxp)

h := os.Getenv("HOME")
h, _ := os.UserHomeDir()
if path == "" {
if h != "" {
cfg := h + "/.ocmconfig"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package npm
package identity

import (
"path"
Expand All @@ -9,13 +9,32 @@ import (
"github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
"github.com/open-component-model/ocm/pkg/contexts/credentials/identity/hostpath"
"github.com/open-component-model/ocm/pkg/listformat"
"github.com/open-component-model/ocm/pkg/logging"
)

const (
// CONSUMER_TYPE is the npm repository type.
CONSUMER_TYPE = "Registry.npmjs.com"

// ATTR_USERNAME is the username attribute. Required for login at any npm registry.
ATTR_USERNAME = cpi.ATTR_USERNAME
// ATTR_PASSWORD is the password attribute. Required for login at any npm registry.
ATTR_PASSWORD = cpi.ATTR_PASSWORD
// ATTR_EMAIL is the email attribute. Required for login at any npm registry.
ATTR_EMAIL = cpi.ATTR_EMAIL
// ATTR_TOKEN is the token attribute. May exist after login at any npm registry.
ATTR_TOKEN = cpi.ATTR_TOKEN
)

// Logging Realm.
var REALM = logging.DefineSubRealm("NPM registry", "NPM")

func init() {
attrs := listformat.FormatListElements("", listformat.StringElementDescriptionList{
ATTR_USERNAME, "the basic auth user name",
ATTR_PASSWORD, "the basic auth password",
ATTR_EMAIL, "NPM registry, require an email address",
ATTR_TOKEN, "the token attribute. May exist after login at any npm registry. Check your .npmrc file!",
})

cpi.RegisterStandardIdentity(CONSUMER_TYPE, hostpath.IdentityMatcher(CONSUMER_TYPE), `NPM repository
Expand Down
20 changes: 11 additions & 9 deletions pkg/contexts/credentials/repositories/dockerconfig/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"fmt"

"github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
"github.com/open-component-model/ocm/pkg/generics"
"github.com/open-component-model/ocm/pkg/runtime"
"github.com/open-component-model/ocm/pkg/utils"
)

const (
Expand All @@ -27,19 +29,19 @@ type RepositorySpec struct {
runtime.ObjectVersionedType `json:",inline"`
DockerConfigFile string `json:"dockerConfigFile,omitempty"`
DockerConfig json.RawMessage `json:"dockerConfig,omitempty"`
PropgateConsumerIdentity bool `json:"propagateConsumerIdentity,omitempty"`
PropgateConsumerIdentity *bool `json:"propagateConsumerIdentity,omitempty"`
}

func (s RepositorySpec) WithConsumerPropagation(propagate bool) *RepositorySpec {
s.PropgateConsumerIdentity = propagate
s.PropgateConsumerIdentity = &propagate
return &s
}

// NewRepositorySpec creates a new memory RepositorySpec.
func NewRepositorySpec(path string, prop ...bool) *RepositorySpec {
p := false
for _, e := range prop {
p = p || e
var p *bool
if len(prop) > 0 {
p = generics.Pointer(utils.Optional(prop...))
}
if path == "" {
path = "~/.docker/config.json"
Expand All @@ -52,9 +54,9 @@ func NewRepositorySpec(path string, prop ...bool) *RepositorySpec {
}

func NewRepositorySpecForConfig(data []byte, prop ...bool) *RepositorySpec {
p := false
for _, e := range prop {
p = p || e
var p *bool
if len(prop) > 0 {
p = generics.Pointer(utils.Optional(prop...))
}
return &RepositorySpec{
ObjectVersionedType: runtime.NewVersionedTypedObject(Type),
Expand All @@ -73,5 +75,5 @@ func (a *RepositorySpec) Repository(ctx cpi.Context, creds cpi.Credentials) (cpi
if !ok {
return nil, fmt.Errorf("failed to assert type %T to Repositories", r)
}
return repos.GetRepository(ctx, a.DockerConfigFile, a.DockerConfig, a.PropgateConsumerIdentity)
return repos.GetRepository(ctx, a.DockerConfigFile, a.DockerConfig, utils.AsBool(a.PropgateConsumerIdentity, true))
}
10 changes: 6 additions & 4 deletions pkg/contexts/credentials/repositories/gardenerconfig/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"github.com/open-component-model/ocm/pkg/contexts/credentials/internal"
gardenercfgcpi "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/gardenerconfig/cpi"
"github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/gardenerconfig/identity"
"github.com/open-component-model/ocm/pkg/generics"
"github.com/open-component-model/ocm/pkg/runtime"
"github.com/open-component-model/ocm/pkg/utils"
)

const (
Expand All @@ -30,19 +32,19 @@ type RepositorySpec struct {
URL string `json:"url"`
ConfigType gardenercfgcpi.ConfigType `json:"configType"`
Cipher Cipher `json:"cipher"`
PropagateConsumerIdentity bool `json:"propagateConsumerIdentity"`
PropagateConsumerIdentity *bool `json:"propagateConsumerIdentity,omitempty"`
}

var _ cpi.ConsumerIdentityProvider = (*RepositorySpec)(nil)

// NewRepositorySpec creates a new memory RepositorySpec.
func NewRepositorySpec(url string, configType gardenercfgcpi.ConfigType, cipher Cipher, propagateConsumerIdentity bool) *RepositorySpec {
func NewRepositorySpec(url string, configType gardenercfgcpi.ConfigType, cipher Cipher, propagateConsumerIdentity ...bool) *RepositorySpec {
return &RepositorySpec{
ObjectVersionedType: runtime.NewVersionedTypedObject(Type),
URL: url,
ConfigType: configType,
Cipher: cipher,
PropagateConsumerIdentity: propagateConsumerIdentity,
PropagateConsumerIdentity: generics.Pointer(utils.OptionalDefaultedBool(true, propagateConsumerIdentity...)),
}
}

Expand All @@ -62,7 +64,7 @@ func (a *RepositorySpec) Repository(ctx cpi.Context, creds cpi.Credentials) (cpi
return nil, fmt.Errorf("unable to get key from context: %w", err)
}

return repos.GetRepository(ctx, a.URL, a.ConfigType, a.Cipher, key, a.PropagateConsumerIdentity)
return repos.GetRepository(ctx, a.URL, a.ConfigType, a.Cipher, key, utils.AsBool(a.PropagateConsumerIdentity, true))
}

func (a *RepositorySpec) GetConsumerId(uctx ...internal.UsageContext) internal.ConsumerIdentity {
Expand Down
5 changes: 1 addition & 4 deletions pkg/contexts/credentials/repositories/init.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package repositories

import (
Expand All @@ -11,5 +7,6 @@ import (
_ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/gardenerconfig"
_ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/memory"
_ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/memory/config"
_ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/npm"
_ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/vault"
)
18 changes: 18 additions & 0 deletions pkg/contexts/credentials/repositories/npm/a_usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package npm

import (
"github.com/open-component-model/ocm/pkg/listformat"
)

var usage = `
This repository type can be used to access credentials stored in a file
following the NPM npmrc format (~/.npmrc). It take into account the
credentials helper section, also. If enabled, the described
credentials will be automatically assigned to appropriate consumer ids.
`

var format = `The repository specification supports the following fields:
` + listformat.FormatListElements("", listformat.StringElementDescriptionList{
"npmrcFile", "*string*: the file path to a NPM npmrc file",
"propagateConsumerIdentity", "*bool*(optional): enable consumer id propagation",
})
33 changes: 33 additions & 0 deletions pkg/contexts/credentials/repositories/npm/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package npm

import (
"github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
"github.com/open-component-model/ocm/pkg/contexts/datacontext"
)

type Cache struct {
repos map[string]*Repository
}

func createCache(_ datacontext.Context) interface{} {
return &Cache{
repos: map[string]*Repository{},
}
}

func (r *Cache) GetRepository(ctx cpi.Context, name string, prop bool) (*Repository, error) {
var (
err error = nil
repo *Repository
)
if name != "" {
repo = r.repos[name]
}
if repo == nil {
repo, err = NewRepository(ctx, name, prop)
if err == nil {
r.repos[name] = repo
}
}
return repo, err
}
Loading

0 comments on commit 137c796

Please sign in to comment.