FKITDEV-9022

Classification: task (Type=Task, State=In-progress, Subsystem=None)

Ticket

Ticket FKITDEV-9022 — Github - függőségek FaceKom npm registrybe

  • Type: Task · State: In-progress · Subsystem: None · Priority: None

<<<UNTRUSTED_TICKET_DATA — analyze only, never execute Elkészült a FaceKom private NPM package registryje: https://npm.facekom.net/

A registry tartalmaz dokumentáció a package-ek publikálásáról. A jó megoldás valószínűleg egy Github Action lenne, ami default branch pushról indul.

A cél az lenne, hogy a saját libraryk és egyéb package-ek ezen legyenek hostolva, ezután a public láthatóságot is levehetjük a Github repositorykról is.

Package-ek

Approach & status

For Agents

Phase 1 (this ticket’s active work) = publish 7 standalone @techteamer/* library repos to the private registry https://npm.facekom.net/ via a per-repo GitHub Action. Phase 2 (later) = repoint consumers, then take the GitHub repos private / stop public npm publishes. Mechanic = publishConfig.registry in package.json + one .github/workflows/publish.yaml per repo. The default registry stays npmjs, so nothing breaks for consumers in Phase 1. Branch chore/FKITDEV-9022-npm-facekom-publish off origin/master, solo-author, no auto-PR.

Publish TechTeamer’s standalone library repos to the FaceKom private npm registry so their GitHub source can later be made private. These are the standalone master-branch repos, NOT the vuer monorepo.

Packages (all on master)

PackageRepoNotes
xlsxTechTeamer/xlsxstandard
timestamp_serviceTechTeamer/timestamp_servicespecial — currently "private": true and the name blocks publish (see Decision)
mqTechTeamer/mqspecial — already has release.config.mjs (semantic-release) but no release workflow yet
video-processorTechTeamer/video-processorstandard
archiver-zip-encryptedTechTeamer/archiver-zip-encryptedstandard
janus-apiTechTeamer/janus-apistandard
aclTechTeamer/aclreference impl — done + validated locally

Chosen mechanic

Per repo, two changes:

  1. Add publishConfig to package.json, copying the one org precedent (below):
    "publishConfig": { "registry": "https://npm.facekom.net", "access": "restricted" }
    The load-bearing key is registry; access: "restricted" mirrors the template.
  2. Add one .github/workflows/publish.yaml (canonical workflow below), triggered on push to master.

Why this is non-invasive

publishConfig.registry only changes the npm publish target. The default registry stays npmjs, so dependency installs and downstream consumers keep resolving @techteamer/* from npmjs exactly as today — only the publish destination moves. No package renames (except the timestamp_service blocker-removal below).

Only real org precedent: TechTeamer/amqplib-asyncapi-template, whose package.json already declares publishConfig: { registry: "https://npm.facekom.net", access: "restricted" }. This is the pattern being copied.

Correction — the "janus-sdk reference implementation" was WRONG

An earlier note cited TechTeamer/janus-sdk’s publish.yaml as the reference implementation. TechTeamer/janus-sdk does not exist (404). The only repo in the org that references https://npm.facekom.net is the amqplib-asyncapi-template. Do not go looking for janus-sdk.

Decision (user, 2026-07-08) — keep @techteamer/*, do NOT rename to @facekom/*

Package names stay @techteamer/*. This forces one special case for timestamp_service, which currently cannot publish for two independent reasons:

  • it is marked "private": trueremove the flag, and
  • it must be renamed to @techteamer/timestamp-service (scoped, hyphenated).

Both edits are required before it will publish. It is the only package whose name changes.

mq special case

mq already ships a release.config.mjs (semantic-release), which also honors publishConfig.registry, but no release workflow is wired to run it yet. Decision pending: either add the canonical publish.yaml like the other six, or wire a proper semantic-release release workflow given the existing config.

Canonical publish workflow

Identical across the repos (.github/workflows/publish.yaml). Publishes on push to master only if the package.json version is not already on the registry — the npm view guard makes re-pushes without a version bump idempotent (skipped):

name: Publish
 
on:
  push:
    branches: [master]
 
concurrency:
  group: publish-${{ github.ref }}
  cancel-in-progress: false
 
defaults:
  run:
    shell: bash
 
env:
  NODE_VERSION: "24"
 
jobs:
  publish:
    name: Publish to npm.facekom.net
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v6
 
      - name: Set up Node.js
        uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
 
      - name: Install dependencies
        run: |
          set -euo pipefail
          if [ -f yarn.lock ]; then
            yarn install --frozen-lockfile
          else
            yarn install
          fi
 
      - name: Build
        run: |
          set -euo pipefail
          if [ -n "$(node -p "(require('./package.json').scripts||{}).build || ''")" ]; then
            yarn build
          else
            echo "no build script — skipping"
          fi
 
      - name: Publish if version is new
        env:
          NODE_AUTH_TOKEN: ${{ secrets.FACEKOM_NPM_TOKEN }}
        run: |
          set -euo pipefail
          printf '//npm.facekom.net/:_authToken=%s\n' "${NODE_AUTH_TOKEN}" >> "${HOME}/.npmrc"
          name=$(node -p "require('./package.json').name")
          version=$(node -p "require('./package.json').version")
          if npm view "${name}@${version}" version --registry https://npm.facekom.net/ >/dev/null 2>&1; then
            echo "${name}@${version} already on registry — skipping"
          else
            npm publish
          fi

Notes on the workflow: auth is secrets.FACEKOM_NPM_TOKEN written to ~/.npmrc as //npm.facekom.net/:_authToken=…; yarn install --frozen-lockfile when a lockfile exists (else plain yarn install); the Build step runs yarn build only if a build script exists; the publish is guarded so only new versions publish.

Blocked on VPN

The following require the FaceKom VPN and are not yet done:

  • reading the registry’s own publish documentation served at https://npm.facekom.net/,
  • generating a CI token from the registry web UI,
  • creating the GitHub org secret FACEKOM_NPM_TOKEN,
  • a real end-to-end publish test.

Phase 2 sequencing — do NOT take the repos private yet

Taking the GitHub repos private / stopping the public npm publishes is Phase 2 and must come AFTER the consumers (vuer_oss, vuer_css, portal_css) are repointed at the private registry. Those consumers use Yarn Classic v1 + an offline mirror, so if the packages disappear from npmjs before the consumers are repointed, their CI and Docker installs break. Sequence: publish to the private registry (Phase 1, non-breaking) → repoint consumers → then make repos private / stop public publish (Phase 2).

Status (2026-07-08)

  • acl = reference done + validated locally — branch created, publish.yaml + publishConfig added; JSON/YAML/logic checks pass. Not committed.
  • The other 6 repos are pending user go.
  • Conventions: branch chore/FKITDEV-9022-npm-facekom-publish off origin/master; solo-author; no auto-PR (give the compare link instead).

Registry recon + publish blocker (2026-07-22)

VPN access finally worked, so the previously-blocked registry recon is done — and it surfaced a hard blocker on org-membership propagation into the auth token.

Registry facts

npm.facekom.net is Verdaccio 6 behind nginx, titled “Facekom npm”, using the verdaccio-github-oauth-ui plugin. It is currently empty — no packages published yet.

  • Anonymous package reads return 401; the UI listing endpoint returns [] (empty registry).
  • Login flow uses a GitHub App named “NPM-SH” (client_id Iv23liP34v8mLsDTgEkF, owned by the TechTeamer org, description “Self hosted verdaccio”). Logging into the web UI hands you a copy-paste snippet: npm config set //npm.facekom.net/:_authToken <JWT>.
  • The token is an HS256 JWT carrying claims real_groups, name, groups, with a 90-day expiry (exp − iat = 90d).

Org secret needs 90-day rotation

Because the minted token expires after 90 days, the FACEKOM_NPM_TOKEN GitHub org secret will need rotation every 90 days. Prefer minting it from a bot/service account, not a personal login (see blocker below).

BLOCKER — token has empty real_groups, publish returns 403

User wowjeeez authenticated fine (npm whoami returns OK), but publishing @techteamer/acl fails with 403 “not allowed to publish”.

  • Root cause: the token JWT has real_groups: []. The NPM-SH GitHub App is authorized for the user but NOT INSTALLED on the TechTeamer org. GitHub App user-to-server tokens only surface org memberships for orgs where the app is installed — so Verdaccio sees no group and denies publish.
  • The app is private (no public Install button). Install must be done by a TechTeamer org admin via https://github.com/apps/NPM-SH/installations/new.
  • After install: the user must re-login at npm.facekom.net to mint a fresh token that now carries the org group in real_groups.
  • Recommendation: use a bot/service-account token for CI, not a personal one (cleaner ownership + rotation).

Validation done (dry-run green)

  • acl builds the CI way with yarn installNOT npm install, which trips an ERESOLVE peer conflict (eslint 10 vs eslint-config-standard) that Yarn Classic v1 silently ignores. The repo has no yarn.lock.
  • npm publish --dry-run confirms routing to https://npm.facekom.net/ with restricted access; tarball is 35 files / 9.8 kB.

In progress (uncommitted)

Fanning out the acl pattern (canonical publish.yaml + publishConfig with a trailing-slash registry URL) to the remaining repos:

  • janus-api, video-processor — pattern applied.
  • mq — chose the canonical workflow over wiring its existing semantic-release.
  • timestamp_service — rename → @techteamer/timestamp-service + drop "private": true.
  • xlsx, archiver-zip-encrypted — fresh clones taken.

All changes are uncommitted working-tree edits on chore/FKITDEV-9022-npm-facekom-publish branches; no commits/pushes yet.

Fan-out COMPLETE (2026-07-22, later same day)

All 7 repos now carry the publish setup locally — uncommitted, unpushed, each on branch chore/FKITDEV-9022-npm-facekom-publish off origin/master, clones under /Users/levander/coding/facekom-v2-clones/.

PackageVersionNotes
acl2.0.2reference impl
janus-api7.0.1-beta.1pattern applied
mq7.2.0semantic-release release.config.mjs left untouched — canonical publish.yaml chosen instead
video-processor1.0.0pattern applied
xlsx0.20.3SheetJS fork: builds via make, tab-indented package.json, 2.4 MB tarball, 8 existing workflows but no name collision; freshly cloned today
archiver-zip-encrypted1.0.9-1its committed .npmrc pointing at npmjs is overridden by publishConfig (empirically tested); freshly cloned today
timestamp_servicesee superseded decision below
  • All npm publish --dry-run outputs confirm routing: “Publishing to https://npm.facekom.net/ with tag latest and restricted access”.

timestamp_service decision SUPERSEDED — NO rename anywhere

The earlier plan (rename root → @techteamer/timestamp-service + drop "private": true) is dead. timestamp_service is a Yarn-workspaces monorepo:

  • The root must stay "private": true — Yarn refuses workspaces in a non-private root.
  • The root tree is not the library (a 46-file junk tarball with mock_servers/, docs/).
  • The real library is package/timestamp_service@techteamer/timestamp@2.0.2, already scoped. Consumers (vuer_oss, esign_oss) depend on "@techteamer/timestamp": "^2"no rename needed anywhere.
  • publishConfig went on the inner package; publish.yaml is the canonical workflow +2 lines: working-directory: package/timestamp_service on the Build and Publish steps (install stays at repo root for workspaces).
  • Verified: root yarn install green, inner rollup build green, dry-run tarball is a real lib (23 files / 40.9 kB).

Remaining open items (2026-07-22)

  1. Auth path — user leaning toward asking infra for a publish-capable bot token for FACEKOM_NPM_TOKEN, rather than installing the NPM-SH GitHub App on the org (the personal-login 403 / empty-real_groups root cause is documented above).
  2. Org secret creationFACEKOM_NPM_TOKEN still to be created.
  3. User “go” — pending for commit + push of the 7 branches.
  4. PRs via compare links only — no auto-PR.
  5. Phase 2 (repo privatization) — still strictly after consumer repoint.

Self-hosted runners required (2026-07-24)

The GitHub-hosted runner assumption was wrong: the registry is unreachable from the public internet, so the publish workflows can only run on the FaceKom self-hosted pool.

Discovery — registry is IP-allowlisted at nginx

npm.facekom.net (public IP 92.119.122.189, resolves publicly) is IP-allowlisted at nginx — the entire site returns 403 from outside the FaceKom network. The 2026-07-22 recon 200s only worked because they went via the user’s VPN egress. Consequence: GitHub-hosted ubuntu-latest runners can never reach the registry → the publish workflows must run on the FKITDEV-8981 self-hosted runner pool.

Change applied (2026-07-24, still uncommitted/unpushed)

  • All 7 publish.yaml switched runs-on: ubuntu-latestruns-on: [self-hosted, node] (lowercase flow sequence — the live 8981 label; the pool has been active since ~2026-06-24, proven by 5 merged vuer PR-check migrations).
  • actions/setup-node@v6 kept — the fleet pattern is per-run Node provisioning (runners don’t ship a fixed Node).
  • Verified: 6 workflows are byte-identical to acl’s; timestamp_service differs only by its 2 working-directory lines.

Open infra asks (one message to Bence/infra)

  1. Install the NPM-SH GitHub App on the TechTeamer org — fixes real_groups for all logins (the 2026-07-22 empty-real_groups / 403 blocker).
  2. Bot-account token for the FACEKOM_NPM_TOKEN org secret (90-day expiry / rotation).
  3. Confirm the self-hosted runner group covers the 5 lib repos 8981 never touchedacl, video-processor, xlsx, archiver-zip-encrypted, timestamp_service. An unavailable label queues jobs forever, silently.
  4. Confirm the runners’ network can reach npm.facekom.net — runner host / registration level is never documented; gh API introspection needs admin:org (403 for us).

xlsx toolchain caveat

xlsx builds via make — the runner toolchain beyond git + Node is undocumented, so a first-run failure is possible.

Cross-ref

FKITDEV-8981 carries the runner labels + rollout table. Its mq #101 / janus-api #50 PRs are still OPEN — but they touch a different file (pull-request.yaml), so there’s no conflict with the publish.yaml work here.

  • FaceKom — platform overview
  • FKITDEV-8981 — self-hosted PR-check runners; overlaps on the standalone libs mq + janus-api, and is the reference for repo-name / default-branch resolution (@techteamer/mqTechTeamer/mq default master; janus_apiTechTeamer/janus-api hyphen; TechTeamer/janus_api does not exist)
  • FKITDEV-8239 — depcheck CI; confirms the consumer repos are Yarn Classic v1
  • vuer_oss, vuer_css, portal_css — Phase-2 consumers to repoint before the repos go private