Metadata-Version: 2.4
Name: cadmould-sdk-auth
Version: 0.1.1
Summary: Login CLI for the cadmould Python SDK — authenticates with your Simcon account and configures pip to install cadmould from the licensed private package index.
Project-URL: Homepage, https://github.com/Simcon-Software/cadmould-sdk-auth
Author: SIMCON kunststofftechnische Software GmbH
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: authentication,cadmould,cli,codeartifact,pip
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.9
Requires-Dist: boto3>=1.34
Description-Content-Type: text/markdown

# cadmould-sdk-auth

Login CLI for the **cadmould** Python SDK. It signs you in with your Simcon account
and configures `pip` so you can install `cadmould` from Simcon's licensed private
package index — no AWS account or AWS CLI required.

## Who can sign in

Sign-in is currently limited to **Simcon staff** — a Simcon Auth0 account on the
`simcon.com` domain. External-customer access (role/entitlement-based) is **not enabled
yet**; it's a later phase. If your sign-in succeeds in the browser but the tool then
reports access denied, your account isn't authorized for the cadmould package index —
contact Simcon support.

## Install

```bash
pipx install cadmould-sdk-auth      # recommended (isolated)
# or: pip install cadmould-sdk-auth
```

## Use

```bash
# activate the virtualenv you want cadmould installed into, then:
cadmould-sdk-auth
pip install cadmould
```

`cadmould-sdk-auth` opens your browser to sign in. On success it writes an
authenticated index URL into the **active virtualenv's** pip config
(`$VIRTUAL_ENV/pip.conf`, or `%VIRTUAL_ENV%\pip.ini` on Windows), so the next
`pip install cadmould` pulls from the private index.

No virtualenv active? Use `--print-index-url` to get the URL and configure pip
yourself, or `--scope user` to write pip's per-user config instead.

**Sign out / manage:**

- `cadmould-sdk-auth --logout` — removes the cadmould index-url entry again (no network
  call), restoring a previous index-url if this tool had replaced one. Exits `3` if the
  current index-url wasn't set by this tool (it's left untouched). It removes the cadmould
  index-url regardless of which `--channel` configured it (pip keeps only one index-url
  per scope), so `--channel` has no effect on `--logout`.
- `--scope user` — applies to the per-user pip config instead of the active venv (works with both the default action and `--logout`).
- `--channel customer|staging` — which distribution channel to authenticate for. Defaults to
  `customer` (the public index). `staging` is an **internal** pre-release channel for Simcon
  staff (gated by Simcon SSO via Entra) and isn't available to external customers.
  **To switch channels, just re-run** with the one you want — it overwrites the active venv's
  single index-url (pip keeps one per scope). For example, switch to staging with
  `cadmould-sdk-auth --channel staging` then `pip install cadmould`, and switch back with
  `cadmould-sdk-auth` (the default `customer` channel).

> Note: writing pip config rewrites the file via `RawConfigParser`, which **drops any
> comments** the file previously contained (settings are preserved). The written file is
> restricted to your user (`0600`; on Windows file modes don't apply — the file gets
> your profile's default ACLs) since it embeds a short-lived token. If you already have
> a custom `index-url`, the tool replaces it and warns you, and `--logout` only removes an
> entry it set (a foreign one is left untouched).
> **Headless / remote machines:** sign-in uses a browser redirect to a loopback address on
> the machine running the CLI, so it won't complete over plain SSH (no local browser) or in
> CI. Run it on a workstation with a browser, or forward the loopback port. (A device-code
> flow is a possible future addition if this is a common need.)

## Using with uv

`uv` does **not** read pip's config (`pip.conf`/`pip.ini`) or `PIP_*` env vars, so the
pip setup above is invisible to it. Instead, declare the private index in your
`pyproject.toml` once, then feed uv a short-lived token via its own credential env vars.

1. Add the index to your `pyproject.toml` (no token — it's committable). Pinning
   `cadmould` to the index keeps uv from resolving a same-named package off public PyPI:

   ```toml
   [[tool.uv.index]]
   name = "cadmould"
   url = "https://cadmould-620794556704.d.codeartifact.eu-central-1.amazonaws.com/pypi/cadmould-python/simple/"
   explicit = true

   [tool.uv.sources]
   cadmould = { index = "cadmould" }
   ```

   For the staging channel use `.../cadmould-python-staging/simple/`. Running
   `cadmould-sdk-auth --channel <ch> --print-env` prints the exact snippet for your
   channel (on stderr) alongside the env exports. A project pins `cadmould` to a
   single index, so use **one channel per project** — don't paste both channels'
   snippets into one `pyproject.toml` (two `[tool.uv.sources]` blocks won't parse,
   and `cadmould` can only resolve from one index). If you work with both channels
   across separate projects, pass a distinct `--uv-index-name` (e.g.
   `cadmould-staging`) for the non-default one so its index name and
   `UV_INDEX_<NAME>_*` credentials don't collide with the default `cadmould`.

2. Authenticate and load the token into uv's per-index credential env vars:

   ```bash
   eval "$(cadmould-sdk-auth --channel staging --print-env)"   # POSIX shells
   uv sync
   ```

   PowerShell:

   ```powershell
   cadmould-sdk-auth --channel staging --print-env --format powershell | iex
   uv sync
   ```

The token is never written to `pyproject.toml` or `uv.lock` — it stays in the env vars.
It's short-lived, so re-run the `--print-env` step when it expires (uv, like pip, does not
re-authenticate mid-resolve).

### Keyring — one setup for your laptop and CI

The env-var method above needs a manual refresh whenever the token expires. uv's
keyring method instead mints a fresh token on **every resolve**, so you only refresh
the *AWS credentials* it derives them from — and the uv config is identical whether
those credentials come from this CLI (your laptop) or an OIDC role (CI). See the
[uv AWS guide](https://docs.astral.sh/uv/guides/integration/aws/).

Keep the `[[tool.uv.index]]` + `[tool.uv.sources]` pin from step 1, then once per
machine:

```bash
uv tool install keyring --with keyrings.codeartifact
export UV_KEYRING_PROVIDER=subprocess
export UV_INDEX_CADMOULD_USERNAME=aws
```

PowerShell:

```powershell
uv tool install keyring --with keyrings.codeartifact
$env:UV_KEYRING_PROVIDER = 'subprocess'
$env:UV_INDEX_CADMOULD_USERNAME = 'aws'
```

The CodeArtifact backend logs a benign `keyringrc.cfg does not exist!` warning until
it has a config file. Create an empty one once (it's also where optional per-repo
settings like `profile`/`region` would go) to silence it — this finds the right path
on any OS:

```bash
uv run --no-project --with keyring python -c "import pathlib, keyring.util.platform_ as p; f=pathlib.Path(p.config_root())/'keyringrc.cfg'; f.parent.mkdir(parents=True, exist_ok=True); f.exists() or f.write_text('# keyrings.codeartifact config\n'); print(f)"
```

On your laptop, load short-lived AWS credentials from this CLI (re-run when they
expire, ~1 h); uv mints CodeArtifact tokens from them automatically:

```bash
eval "$(cadmould-sdk-auth --channel staging --print-aws-env)"   # POSIX shells
uv sync
```

PowerShell:

```powershell
cadmould-sdk-auth --channel staging --print-aws-env --format powershell | iex
uv sync
```

`cadmould-sdk-auth --print-aws-env` also prints these keyring steps for your shell
(on stderr), so you don't have to keep this list to hand.

In CI, drop this CLI entirely and let the runner assume an AWS role (e.g. GitHub
OIDC) with read access to the repo — the **same** keyring + index config then works
unattended, with no token handling at all.

### In a Docker build

Install at **build** time so the wheel is baked into the image and the running container
needs no token at all. Pass the token as a BuildKit secret — never bake it into a layer:

```bash
# mint a fresh token on the host (good for the few minutes a build takes)
export CA_TOKEN="$(cadmould-sdk-auth --channel staging --print-token)"
DOCKER_BUILDKIT=1 docker build --secret id=ca_token,env=CA_TOKEN .
```

```dockerfile
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=ca_token \
    UV_INDEX_CADMOULD_USERNAME=aws \
    UV_INDEX_CADMOULD_PASSWORD="$(cat /run/secrets/ca_token)" \
    uv sync --frozen
```

> Fully unattended CI (no human to complete the browser sign-in) needs a non-interactive
> credential — an Auth0 machine-to-machine client, or a native AWS identity for the CI —
> which is a separate setup, not this CLI.

## How it works

1. **PKCE login** to Simcon's identity provider (loopback redirect; opens your browser).
2. The resulting token is exchanged via **AWS STS** for short-lived, read-only
   credentials to the private package repository.
3. Those mint a **CodeArtifact authorization token**, embedded in the pip index URL.

The token is short-lived; re-run `cadmould-sdk-auth` when it expires. The tool only
ever obtains **read** access to the cadmould package index.

**If a long install fails with `401 Unauthorized`:** pip does **not** re-authenticate
mid-install, so if the token expires while a large download is in progress, the
install fails. Re-run `cadmould-sdk-auth` to get a fresh token, then restart the
`pip install` (already-downloaded wheels are cached, so the retry is fast).

## License

[Apache License 2.0](LICENSE). (The cadmould SDK itself is proprietary, licensed
software — this tool only handles sign-in and pip configuration.)
