Cloud sweep: mask secret-looking prompts, #16 split, skills + AI-first README, sdist skill fix, PyPI metadata - #31
Merged
Conversation
…es); drop dead code Documentation-only half of the #16 audit omnibus. No behaviour change. - codecs: warn that .pkl/.pickle decode with pickle.loads (arbitrary code execution on untrusted bytes); replace the eval() in register_codec's example. - base: get_config docstring warns about the broad (Exception,) default; remove the dead commented-out OPENAI_API_KEY/getpass block. - tools/s_configparser: state the current silent-empty behaviour of extract_exports and ConfigReader for missing paths, the os.path.sep-based path detection, and the import-time folder creation. The behaviour changes are split into #25, #26, #27, #28 and #29. Fixes #16
Member
Author
|
cloud-status: started — baseline 132/0/4 (dependents: py2store 80/0/1, xdol 61/2, oa 41/3, all failures pre-existing); plan: #13 key-aware masking plus a piped-stdin guard, #16 docs split (done, filed #25-#29), #12 analysis comment, consumer and dev skills plus AI-first README. Generated by Claude Code |
…sking ask_user_for_input (and so the simple_config_getter/config_getter prompt-for-missing-key flow) echoed every typed value, secrets included. - DFLT_MASKING_INPUT is now looks_like_secret: prompts mentioning secret/token/pass/pwd/api/key/credential/auth/private are masked, others (file paths, names) still echo. mask_input accepts a bool or a prompt -> bool predicate; explicit True/False behave as before. - Masked reads use input() when stdin is not a terminal and getpass is the stdlib one: stdlib getpass reads /dev/tty, not stdin, so piped input was ignored (or the call hung). A frontend's replacement getpass (Jupyter's masked widget) is always used. Tests: config2py/tests/test_masking.py (17). Verified under a real pty that typed secrets no longer appear in terminal output, and that piped input with a controlling tty is read instead of hanging. Dependents py2store, xdol and oa match their baselines. Fixes #13
- license = "Apache-2.0" (PEP 639) plus license-files, replacing the deprecated [project.license] table; no License :: classifier. - Classifiers for Python 3.10-3.13 (suite verified on each), keywords, author, and Documentation/Repository/Issues URLs (docs site checked live). - build-system floor hatchling>=1.27, the first release with PEP 639 support. Dependencies, version and CI are unchanged; setup.cfg removal and the CI stub migration stay in #22. twine check passes on the sdist and wheel, and the CI version-bump regex still targets [project].version only.
- config2py/data/skills/config2py-quickstart: how to use the package (entry points, get_config, simple_config_getter, user_gettable, app folders, FileStore, ConfigStore, codecs, gotchas). Ships in the wheel. Every Python snippet was run. - skills/config2py-dev: how to work on it (module map, CI-matching test command, test isolation, dependents gate, open design issues, release flow). - .claude/skills/<name>: relative symlinks so Claude Code loads both. - pyproject: [tool.hatch.build.targets.sdist] excludes .claude/skills with skip-excluded-dirs. hatchling walks with followlinks=True and skips inodes it has seen, so the symlinks made it drop config2py/data/skills from the sdist, and so from the wheel CI builds from it. test_packaging.py checks the sdist file list whenever hatchling is importable. - .claude/CLAUDE.md: agent-layer notes, the #16 follow-up issues, the dependents gate, and current test counts. Both skills pass skill.validate with no issues.
…amples - Top: what the package does, a link to the human section at the end, then "What an agent can do" with a minimal runnable example and the pip route to the bundled skill. The epythet agentic section was regenerated with `epythet ai-readme-check . --write` and now lists the skills and CLAUDE.md. - Fixed examples: FileStore on a fresh file and nested key_path need create_file_content / create_key_path_content, the register_extension import is now config2py.sync_store, placeholder functions are replaced by runnable ones, and a duplicated paragraph is removed. The prompt now documents the masking behaviour. - New section at the end for human developers: dev setup, design rationale, contributing, where to ask. - config2py/tests/test_docs_examples.py runs every python block and >>> example of README.md and of the consumer skill, in a subprocess with a sandboxed HOME and closed stdin. Blocks that must prompt carry a <!-- no-test --> marker. The old README examples fail this test. Fixes #32
The adversarial review of #31 found a regression: the stdin fallback applied to every masked read, so an explicit mask_input=True with a terminal present and stdin piped read the first piped line as the secret. Stdlib getpass reads /dev/tty on purpose there, as sudo does. The fallback now applies only when masking was inferred by a predicate (the new default), which keeps both paths identical to master: explicit True reads the terminal, and a defaulted prompt reads stdin as the old echoing default did. Verified under a real pty. The docstrings now also say that looks_like_secret is a substring match on the whole prompt. Refs #13
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tests
Command, matching CI:
python -m pytest config2py --doctest-modules -o doctest_optionflags='ELLIPSIS IGNORE_EXCEPTION_DETAIL' -qtest_packaging.py, which needs hatchling. With hatchling installed the suite gives 156 passed, 4 skipped.wads ci-localpasses: ruff, tests on 3.10 and 3.12, anduv build.Dependents were run against the working tree before and after each code change:
The xdol and oa failures exist on master too. xdol's two are doctest-format failures. oa's three need a real OpenAI key.
Changes
docs (Minor audit findings (omnibus): docstring overclaims, broad fallback, pickle codec, import-time side effects #16): pickle-decode security warnings, and a warning about the broad
(Exception,)fallback. Docstrings now state the silent-empty behaviours for missing paths, theos.path.sepdetection and the import-time folder creation. Removed dead commented-out code. No behaviour change.fix (Default
mask_input=Falseechoes secrets to terminal insimple_config_getterflow #13):DFLT_MASKING_INPUTis nowlooks_like_secret, so secret-looking prompts are masked and other prompts still echo.mask_inputaccepts a bool or aprompt -> boolpredicate.getpasswould read/dev/tty. Jupyter's replacementgetpassis always honoured.test_masking.py.packaging: SPDX
license = "Apache-2.0"pluslicense-files, classifiers for 3.10 to 3.13, keywords, author, and the Documentation, Repository and Issues URLs.hatchling>=1.27for PEP 639.twine checkpasses, and CI's version-bump regex still hits[project].versiononly.agent layer:
config2py/data/skills/config2py-quickstart, which ships in the wheel.skills/config2py-dev, plus relative symlinks in.claude/skills/. Both skills passskill.validate.exclude = [".claude/skills"]andskip-excluded-dirs = truethe real skill folders were dropped from the sdist, and so from the wheel.test_packaging.pyguards this..claude/CLAUDE.mdis updated.docs (README SyncStore examples fail as written (missing file, missing key_path, wrong import) #32): the README is now AI-first:
test_docs_examples.pyruns every Python block and>>>example of the README and the consumer skill in a sandboxed HOME.fix (from review): an explicit
mask_input=Truekeeps reading the terminal when stdin is piped, as on master.Issues
mask_input=Falseechoes secrets to terminal insimple_config_getterflow #13, Minor audit findings (omnibus): docstring overclaims, broad fallback, pickle codec, import-time side effects #16 (the docs half; the rest is split out) and README SyncStore examples fail as written (missing file, missing key_path, wrong import) #32.needs-localbecause of Windows.egress, which interacts withoa.0o644, a gap left by fix: create config files/dirs owner-only (0o600/0o700), not umask-default #21.needs-local.needs-local.Not done, and why
get_app_data_folder.setup.cfgremoval and the CI stub were left to that PR, which is blocked on manual-task: hosted CI stuck at action_required on doctor/setup-cfg-and-wads-ci (PR #22) #23 and needs web-UI approval.skillpackage skipped steps that need the user's machine ($PP,~/.claude).Adversarial review (Opus subagent)
Round 1: BLOCK. Findings, and what I did about each:
mask_input=Trueread piped stdin instead of the terminal, so the first piped line was saved as the secret. Fixed in 3c54bef: the stdin fallback now applies only when masking is inferred. A new test failed before the fix, and a real pty check now matches master.builtins.inputhang underpytest -sin a terminal when they ask for a secret-looking key. Captured runs and CI are fine. Release note below.looks_like_secretis a plain substring match, soKEYS_DIRandAUTHORare masked too. Documented in the docstring and the skill. I kept the design, since masking too much is the safer error.Round 2 (3c54bef): APPROVE. The fix was verified, and the toggle path behaves like master. Its one non-blocking note is that toggling back to masked uses
getpass, which is master behaviour.For whoever lands it
mask_input=Falseto echo them. Tests that patch onlybuiltins.inputshould also patchgetpass.getpass(seeconfig2py.tests.utils_for_testing.user_input_patch).pyproject.toml, so expect a small conflict with chore: remove vestigial setup.cfg, add [tool.wads.ci], migrate CI to the stub #22.Fixes #13
Fixes #16
Fixes #32
🤖 Generated with Claude Code