Skip to content

feat(auth): --repo for dt auth setup (0.20.0) - #177

Merged
johnyaku merged 2 commits into
mainfrom
feat/auth-setup-repo
Aug 13, 2026
Merged

johnyaku merged 2 commits into
mainfrom
feat/auth-setup-repo

Conversation

@johnyaku

Copy link
Copy Markdown
Contributor

Adds --repo to dt auth setup, mirroring the option on dt auth check and dt auth list.

Those two could already inspect a repository you had not cloned, but there was no way to acquire the access they told you that you lacked without cloning first. That is the wrong shape for dt get, whose point is fetching data with no tracked working copy.

dt auth setup --repo git@github.com:org/data-repo.git
dt auth setup --repo data-repo          # short name, via `owner`

The repo is shallow-cloned to a temp dir purely to read its config, so this runs from anywhere — including a directory that is not a git repo.

Credentials had to be scoped, not just discovered

install_credentials() with no argument discovers repos from the current directory, which under --repo is a different project entirely — it would fetch the wrong secrets. _s3_secret_names maps each discovered S3 endpoint back to the repo that owns it: a top-level remote belongs to the named repo, a nested one to the import source above it.

That second case matters. A repo whose data comes from an import needs the source repo's credentials too, or the fetch fails on exactly the paths the caller came for.

Also fixed: a crash that broke all three auth commands

Verifying this on real data immediately hit an unrelated, unhandled crash:

TypeError: expected str, bytes or os.PathLike object, not list

remote.root is a list key — dt config add remote.root <path> promotes a scalar to a list, and dt/remote.py has always read it through cfg.get_str_list. Endpoint discovery was the one consumer still treating it as a scalar. The site config here sets eight roots, so dt auth list, dt auth check and dt auth setup were all crashing outright with a traceback for everyone using it. It is a separate bug, but it blocked the feature, so it is the first commit rather than a separate PR.

The fix goes through remote_mod.remote_roots() and offers the roots that actually hold the project, falling back to the first — where dt remote init would create it — when none do. For bcarc_wts that correctly surfaces two roots.

Also: a missing SSH username no longer says nothing

click.prompt aborts with an empty message on a closed stdin, which surfaced as a bare SSH setup error: — no host, no cause, no remedy. Non-interactive runs are the norm for this flag, so it now names the host and points at -u.

Verification

  • 2017 passed, 1 skipped (tests/unit) — 20 new tests, no regressions
  • All three fixes mutation-tested: each reverted individually and confirmed to fail. The credential-scoping test was strengthened after the first attempt failed on a stub's signature rather than its assertion
  • Exercised end-to-end against real repos from a non-git directory: bcarc_wts correctly resolves to the single secret bcarc_wts, and a real CLI run against a no-S3 repo left ~/.aws/credentials untouched

tests/integration/test_clone_cmd.py hangs on network access to GitHub from the login node — confirmed identical on main (4m0.015s) and this branch (4m0.167s), so it is pre-existing and unrelated.

Closes nothing — no issue was filed for this.

🤖 Generated with Claude Code

johnyaku and others added 2 commits August 13, 2026 10:24
`remote.root` is a list key -- `dt config add remote.root <path>` promotes
a scalar to a list on first use, and `dt/remote.py` has always read it
through `cfg.get_str_list`. Endpoint discovery was the one consumer still
treating it as a plain string, so `Path(remote_root)` raised

    TypeError: expected str, bytes or os.PathLike object, not list

as soon as a second root was configured. That crashed `dt auth list`,
`dt auth check` and `dt auth setup` outright, with a traceback rather than
an error -- and the site config here configures eight roots, so all three
were broken for everyone using it.

Go through `remote_mod.remote_roots()`, the shared accessor. A project's
remote lives under one of the roots, so offer the roots that actually hold
it, falling back to the first -- which is where `dt remote init` would
create it -- when none do.

Co-Authored-By: Claude <noreply@anthropic.com>
`dt auth check --repo` and `dt auth list --repo` could already inspect a
repository you had not cloned; `dt auth setup` could not, so there was no
way to *acquire* the access those commands told you that you lacked
without first cloning. That is the wrong shape for `dt get`, whose whole
point is fetching data without a tracked working copy.

`--repo` shallow-clones the repo to a temp dir purely to read its config,
so it runs from anywhere -- including a directory that is not a git repo.

Credentials need scoping to match. `install_credentials()` with no
argument discovers repos from the *current directory*, which under
`--repo` is a different project entirely, so the secrets fetched would be
the wrong ones. `_s3_secret_names` maps each discovered S3 endpoint back
to the repo that owns it instead: a top-level remote belongs to the named
repo, a nested one to the import source above it. A repo whose data comes
from an import needs the source repo's credentials too, or the fetch
fails on exactly the paths the caller came for.

Also make a missing SSH username explain itself. `click.prompt` aborts
with an empty message on a closed stdin, which surfaced as a bare
"SSH setup error:" -- no host, no cause, no remedy. Non-interactive runs
are the norm for this flag, so say what is missing and how to supply it.

Co-Authored-By: Claude <noreply@anthropic.com>
@johnyaku
johnyaku merged commit 45db13e into main Aug 13, 2026
1 check passed
@johnyaku
johnyaku deleted the feat/auth-setup-repo branch August 13, 2026 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant