mirror of
https://github.com/d9pouces/id_configurator.git
synced 2026-11-09 01:47:21 +01:00
db4ff3cfd4
Signed-off-by: d9pouces <github@19pouces.net>
85 lines
3.7 KiB
Python
85 lines
3.7 KiB
Python
"""Configure npm to use the configured NpmRepository entries: the first one
|
|
replaces the default registry, and any further ones are registered scoped to
|
|
their own name (`@name:registry`), e.g. for a private org's packages
|
|
alongside the default public registry.
|
|
|
|
Unlike Composer or pip, npm (via Node.js) does not trust the system CA store
|
|
by default - Node bundles its own root CA list - so this also points npm's
|
|
own `cafile` setting at the bundle the `certificates` module writes. Unlike
|
|
Poetry's per-repository certificate, `cafile` is a single, global npm
|
|
setting.
|
|
|
|
Written to npm's "global" config file (what `npm config --global` edits),
|
|
`$prefix/etc/npmrc` - not the "user" config, `$HOME/.npmrc`, which is a
|
|
separate, higher-precedence level in npm's own terminology. `$prefix`
|
|
defaults to `/usr/local` for essentially every standard Node.js install
|
|
(the official Docker image included); unlike a config dropped in one
|
|
specific user's home, this applies regardless of which user invokes npm.
|
|
|
|
`cafile` only covers npm's own registry client, though - it does nothing for
|
|
Node itself, e.g. a package's install script or the application's own code
|
|
making an HTTPS request. Node has no config file for that: the only way to
|
|
extend its trust store is the `NODE_EXTRA_CA_CERTS` environment variable,
|
|
read once at process startup. So whenever any certificate is configured -
|
|
regardless of whether any npm repository is - it is also set system-wide in
|
|
`/etc/environment` (merged with whatever is already there), which every
|
|
login-based process (an SSH session, `su -`, ...) picks up via PAM's
|
|
`pam_env`. This does not reach a `docker build`/`RUN` step or a container's
|
|
own `ENTRYPOINT`/`CMD`, which never go through a login shell: propagating it
|
|
there is the resulting image's own `Dockerfile`'s job (a plain `ENV`
|
|
instruction), outside what a tool that only writes files can do.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from id_configurator.config import NpmRepository
|
|
from id_configurator.context import Context
|
|
from id_configurator.modules.base import Module, register
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_NPMRC = "usr/local/etc/npmrc"
|
|
_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt"
|
|
_ETC_ENVIRONMENT = "etc/environment"
|
|
_NODE_EXTRA_CA_CERTS_VAR = "NODE_EXTRA_CA_CERTS"
|
|
|
|
|
|
def _write_npmrc(context: Context, repositories: list[NpmRepository]) -> None:
|
|
lines = [f"cafile={_CA_BUNDLE}", f"registry={repositories[0].url}"]
|
|
lines.extend(
|
|
f"@{repository.name}:registry={repository.url}"
|
|
for repository in repositories[1:]
|
|
)
|
|
context.write_file(_NPMRC, ("\n".join(lines) + "\n").encode("utf-8"))
|
|
logger.info("configured npm to use %s", repositories[0].url)
|
|
|
|
|
|
def _update_etc_environment(context: Context) -> None:
|
|
existing = context.read_src_file(_ETC_ENVIRONMENT)
|
|
lines = [] if existing is None else existing.decode("utf-8").splitlines()
|
|
lines = [
|
|
line for line in lines if not line.startswith(f"{_NODE_EXTRA_CA_CERTS_VAR}=")
|
|
]
|
|
lines.append(f"{_NODE_EXTRA_CA_CERTS_VAR}={_CA_BUNDLE}")
|
|
context.write_file(_ETC_ENVIRONMENT, ("\n".join(lines) + "\n").encode("utf-8"))
|
|
logger.info("configured %s in %s", _NODE_EXTRA_CA_CERTS_VAR, _ETC_ENVIRONMENT)
|
|
|
|
|
|
@register
|
|
class NpmModule(Module):
|
|
name = "npm"
|
|
|
|
def is_relevant(self, context: Context) -> bool:
|
|
return bool(context.config.configurations.npm.repositories) or bool(
|
|
context.config.configurations.certificates
|
|
)
|
|
|
|
def apply(self, context: Context) -> None:
|
|
repositories = context.config.configurations.npm.repositories
|
|
if repositories:
|
|
_write_npmrc(context, repositories)
|
|
if context.config.configurations.certificates:
|
|
_update_etc_environment(context)
|