npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@devix-tecnologia/npm-registry

v0.1.0

Published

Registry npm privado e seguro (Verdaccio) para CapRover: receita one-click genérica, isolamento de rede e as auditorias que a mantêm segura

Readme

@devix-tecnologia/npm-registry

@devix-tecnologia/npm-registry

Registry npm privado e endurecido, para qualquer pessoa ou organização subir no CapRover em one-click: Verdaccio sem cadastro aberto, sem acesso anônimo, com versões imutáveis e saída para a internet só por um proxy com allowlist. Nada na receita nem nas imagens é de uma organização: escopo, URL e usuários entram no formulário.

Este pacote traz a receita one-click, o catálogo de variáveis de ambiente das imagens e as auditorias que mantêm a receita segura e genérica. As imagens moram no docker/ da raiz do repositório (docker/verdaccio, docker/verdaccio/nginx, docker/proxy-allowlist).

Origem e decisões: TASKS/task-006.

Arquitetura

internet ─► captain-nginx ─► nginx (entrada) ─┐
                                               ├─ rede interna ── verdaccio
internet ◄── proxy (saída, allowlist) ◄────────┘

| Serviço | Imagem | O que faz | | --- | --- | --- | | <app>-verdaccio | devix-verdaccio | O registry. Configuração inteira por env, regerada a cada boot; derruba o boot diante de configuração insegura. | | <app>-proxy | devix-proxy-allowlist | Squid só com CONNECT 443 para o host do uplink. Nega e registra o resto. | | <app> | devix-verdaccio-nginx | O único serviço exposto. Proxy reverso; nega as rotas do npm unpublish; limita o corpo; log JSON. |

O que o registry garante

| Garantia | Como | Testado em | | --- | --- | --- | | Ninguém se cadastra sozinho | max_users: -1; npm adduser recebe 409 | integração | | Sem acesso anônimo | nenhuma regra com $all/$anonymous; o entrypoint recusa se aparecer | --check e integração | | Só quem está em VERDACCIO_PUBLICADORES publica | $authenticated não é aceito como publicador | --check e integração | | Versão publicada é imutável | republicar dá 409; unpublish dá 403 no nginx e no Verdaccio, para todos | integração | | Senha só em bcrypt | hash gerado pela imagem; a lista de usuários só aceita hash, com custo mínimo | --check | | O Verdaccio não sai para a internet por conta própria | rede interna sem rota; a saída é o proxy, com allowlist | integração (compose) e e2e (CapRover 1.15) |

Duas armadilhas do Verdaccio que a imagem contorna

  • unpublish: false não nega nada. No Verdaccio 6, false ou lista vazia em unpublish contam como "não definido", e a permissão cai na de publish: quem publica, despublica. A imagem põe em unpublish um grupo que nenhum usuário pode ter (ninguem:imutavel — o : é proibido em nome de usuário).
  • O secret do JWT não vem do config.yaml. Ele mora no .verdaccio-db.json, dentro do storage. O script init/02-secret.sh grava ali o valor da env a cada boot, então trocar VERDACCIO_SECRET e reiniciar invalida todos os tokens.

Limites que não têm conserto por configuração

  • npm deprecate também é recusado. O Verdaccio trata deprecação como unpublish. Com a imutabilidade, depreciar fica bloqueado — coerente, já que reescreveria os metadados de uma versão publicada. Para avisar quem consome, publique uma versão nova ou mova uma dist-tag (npm dist-tag funciona).
  • Publicar um nome que já existe no uplink é aceito. A rota de publish do Verdaccio ignora o 409 da checagem do uplink. Regra operacional: num escopo com proxy, nunca publique aqui um nome que exista lá — a versão local se misturaria à pública. Um teste de caracterização avisa se uma versão futura do Verdaccio passar a recusar.
  • O one-click não isola a rede sozinho. Todo app do CapRover nasce na captain-overlay-network, que tem saída para a internet, e a receita não consegue declarar outra rede. O isolamento é um passo depois do deploy (ver "Isolamento de rede"); até ele, a saída pelo proxy é só configuração.

Subir no CapRover

  1. Publique as três imagens num registry que o CapRover alcance (docker/docker-compose.build.yml, perfil bases).
  2. Em Apps → One-Click Apps/Databases → TEMPLATE, cole templates/one-click-app.yml.
  3. Preencha pelo menos:
    • URL pública (https://npm.suaempresa.com);
    • escopos com proxy: só os que a sua organização possui no registry de origem; ou escopos locais, sem proxy;
    • quem publica. As senhas e o secret vêm gerados. O nome do app não pode ser registry nem captain: são nomes reservados do CapRover, que recusa o deploy.
  4. Depois do deploy, obrigatório:
    • no app <app> (o nginx), configure o domínio, habilite HTTPS e marque Force HTTPS — até lá, senha e token trafegam em claro;
    • aplique o isolamento de rede (próxima seção).

Isolamento de rede

Depois do one-click, o Verdaccio ainda alcança a internet direto. O isolamento o prende numa rede overlay sem rota para fora; o proxy e o nginx ficam nas duas redes, como fronteiras de saída e de entrada.

# 1. no servidor do CapRover (a API dele não cria rede)
docker network create --driver overlay --internal --attachable npm-interna

# 2. de qualquer máquina que alcance o painel
CAPROVER_SENHA='senha-do-painel' npx @devix-tecnologia/npm-registry isolar \
  --url https://captain.suaempresa.com --app npm --rede npm-interna

O comando troca o Service Update Override dos três apps, pelo definirOverrideDoApp do @devix-tecnologia/caprover-client: as redes do serviço no Swarm, com os aliases srv-captain--<app> pelos quais eles se acham. É idempotente. Comprovado contra o CapRover 1.15 (pnpm test:e2e): o override sobrevive a redeploy, e o CapRover não religa a rede padrão sozinho. Para desfazer, apague o override dos três apps no painel.

Não use o campo de redes do app: no CapRover 1.15 ele é interno, e a rota de atualização não o aceita.

Por que não está na receita. O one-click do CapRover 1.15 não carrega override de rede: de cada serviço, ele só aproveita image, volumes, ports, environment e depends_on; de caproverExtra, só containerHttpPort, notExposeAsWebApp, websocketSupport e dockerfileLines; e, para o override, só hostname, cap_add e command (OneClickAppDeploymentHelper e DockerComposeToServiceOverride no código do servidor). Uma chave networks: ou um serviceUpdateOverride dentro de caproverExtra é descartado em silêncio, e o app sobe na rede padrão. E, mesmo que fosse aceito, a rede interna precisa existir antes, e nem a receita nem a API criam rede. Por isso o isolamento é sempre um passo depois do one-click.

A senha do usuário inicial fica na env VERDACCIO_ADMIN_SENHA do app <app>-verdaccio.

Usuários

A env é a fonte de verdade: o htpasswd é regerado a cada boot.

| Para | Faça | | --- | --- | | Criar | gere o hash e acrescente nome:hash em VERDACCIO_USUARIOS_HTPASSWD; reinicie | | Trocar a senha | troque o hash; reinicie | | Remover | tire o item da lista; reinicie |

htpasswd -nbB maria.souza 'senha-forte-da-maria'

Só hash bcrypt entra na lista: senha em claro ali impede o registry de subir. Nome de usuário não pode ter :, , nem espaço, nem começar com $ ou @. Quem pode criar usuário é quem pode mudar a env no CapRover.

Configurar o cliente

# .npmrc do projeto (versionado)
@suaempresa:registry=https://npm.suaempresa.com/

# token: só por env, nunca no arquivo versionado
//npm.suaempresa.com/:_authToken=${NPM_TOKEN_PRIVADO}

O token sai do login (npm login --registry https://npm.suaempresa.com/). No CI, use um usuário próprio, listado em VERDACCIO_PUBLICADORES.

Pacote privado declara onde publica — sem isso, um npm publish distraído vai para o npmjs:

{
  "publishConfig": {
    "registry": "https://npm.suaempresa.com/",
    "@suaempresa:registry": "https://npm.suaempresa.com/",
    "access": "restricted"
  }
}

O registry do escopo precisa estar também no publishConfig: um @suaempresa:registry no .npmrc prevalece sobre o publishConfig.registry sozinho.

Rotações e incidente

| Situação | Ação | | --- | --- | | Token vazou | troque VERDACCIO_SECRET (32 caracteres) e reinicie: todos os tokens caem | | Senha vazou | troque o hash do usuário (ou VERDACCIO_ADMIN_SENHA) e reinicie; troque também o secret, porque tokens emitidos continuam válidos até expirar | | Usuário saiu | tire da lista e reinicie; troque o secret pelo mesmo motivo | | Saída suspeita | o log do proxy lista cada destino (TCP_TUNNEL passou, TCP_DENIED foi barrado) |

Ambiente local

# imagens (da raiz do repositório); as finais fazem FROM da base local
docker build -f docker/verdaccio/Dockerfile.base -t devix-verdaccio-base:6.10.5-1 docker/verdaccio
docker build -t devix-verdaccio:6.10.5-1 docker/verdaccio
docker build -f docker/nginx/Dockerfile.base -t devix-nginx-base:1.27-alpine-1 docker/nginx
docker build -t devix-verdaccio-nginx:1.27-alpine-1 docker/verdaccio/nginx
docker build -f docker/proxy/Dockerfile.base -t devix-proxy-base:6.6-24.04-1 docker/proxy
docker build -t devix-proxy-allowlist:6.6-24.04-1 docker/proxy-allowlist

# segredos (ver secrets/README.md) e subida
cd packages/npm-registry
docker compose up -d --wait

VERDACCIO_ESCOPOS, VERDACCIO_PUBLICADORES e as demais variáveis do docker-compose.yml podem vir de um .env ao lado dele.

Testes

| Comando | O que roda | | --- | --- | | pnpm test | catálogo, auditorias da receita e confronto das imagens (ENV dos Dockerfiles, versões, nada de organização embutido) | | pnpm test:integration | builda as imagens, sobe o compose com rede interna e um uplink falso em HTTPS, e exerce o registry pelo npm: autenticação, autorização, imutabilidade, proxy, isolamento de rede, rotação de secret e de senha. Precisa de Docker. MANTER_AMBIENTE=1 deixa o ambiente de pé no fim | | pnpm test:e2e | sobe um CapRover 1.15 de verdade num Docker isolado (dind), instala a receita pelo endpoint de one-click, roda o npm-registry isolar e confere o antes e o depois: saída direta, saída pelo proxy, acesso pelo domínio, unpublish negado e o isolamento depois de um redeploy. Mesmo arranjo do e2e do geohub. Precisa de Docker com container privilegiado e de internet; rode pnpm build antes |

API

import { criarCapRoverClient } from '@devix-tecnologia/caprover-client';
import {
  auditarReceitaDoRegistry,
  isolarNoCapRover,
  lerTextoDaReceita,
} from '@devix-tecnologia/npm-registry';

auditarReceitaDoRegistry(lerTextoDaReceita()); // [] = receita aprovada

// O isolamento, como biblioteca (o `npm-registry isolar` usa isto), sobre o
// cliente do CapRover do devix-stack.
const cliente = await criarCapRoverClient({
  appName: 'npm',
  senha: process.env.CAPROVER_SENHA!,
  url: 'https://captain.suaempresa.com',
});
await isolarNoCapRover({ cliente, appName: 'npm', rede: 'npm-interna' });

auditarReceitaDoRegistry roda as regras genéricas do @devix-tecnologia/caprover-stack e as deste pacote:

| Regra | Reprova | | --- | --- | | paridade-com-catalogo | env fora do catálogo, valor que não bate com a origem, default diferente do da imagem, variável que não alimenta nada | | segredo-gerado | credencial com default fixo em vez de $$cap_gen_random_* | | superficie-desligada-por-padrao | interface web ou npm audit ligados por padrão | | servicos-internos-nao-expostos | Verdaccio ou proxy expostos como web app | | sem-colisao-de-prefixo | id de variável que é prefixo de outro (a substituição do CapRover corromperia o longo) | | sem-valor-de-organizacao | valor de organização embutido em env ou default |

Pendências

  • Onde publicar as imagens: os defaults da receita apontam para registry.exemplo.com, como o resto da stack. Para servir a qualquer organização, as imagens precisam estar num registry público.