Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include MANIFEST.in PACKAGE.md pyproject.toml
recursive-include src/password_policy_lab *.css *.html *.py *.typed
prune tests
12 changes: 9 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
PYTHON ?= python3
EVIDENCE_WORK ?= $(CURDIR)/.evidence-work
DISTRIBUTION_WORK ?= .evidence-work/distribution
PLAYWRIGHT_BROWSERS_PATH ?= $(CURDIR)/.playwright-browsers
EVIDENCE_ENV = \
PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" \
Expand All @@ -15,8 +16,8 @@ EVIDENCE_ENV = \
TEMP="$(EVIDENCE_WORK)/tmp"

.PHONY: \
build check dependencies evidence evidence-browser evidence-check lint test \
typecheck
build check dependencies distribution-check evidence evidence-browser \
evidence-check lint test typecheck

lint:
@$(PYTHON) -m ruff check app.py scripts src tests
Expand All @@ -38,6 +39,11 @@ build:
dependencies:
@$(PYTHON) -m pip check

distribution-check:
@PYTHONDONTWRITEBYTECODE=1 $(PYTHON) scripts/attest_distribution.py \
--root "$(CURDIR)" \
--work-root "$(DISTRIBUTION_WORK)"

evidence-browser:
@mkdir -p "$(EVIDENCE_WORK)/tmp" "$(EVIDENCE_WORK)/xdg"
@$(EVIDENCE_ENV) $(PYTHON) -m playwright install chromium
Expand All @@ -52,4 +58,4 @@ evidence-check:
"$(EVIDENCE_WORK)/xdg"
@$(EVIDENCE_ENV) PYTHONPATH=src $(PYTHON) scripts/check_evidence.py

check: lint typecheck test dependencies evidence-check
check: lint typecheck test dependencies distribution-check evidence-check
24 changes: 24 additions & 0 deletions PACKAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Password Policy State-Space

`password-policy-state-space` counts constrained visible-ASCII password spaces
exactly and exposes deterministic inspection, rank, and unrank operations. Its
production sampler selects one uniform integer rank with `secrets.randbelow`
and maps that rank to a candidate without retrying invalid strings.

The installed command can inspect a policy without sampling:

```bash
password-policy-lab inspect --length 20 --format json
```

`rank` and `unrank` are reversible and are intended only for explicitly public
test vectors. Both require `--acknowledge-reversible-output`; never use them
with a credential.

The wheel contains the typed Python package, server-rendered template and
stylesheet, and the `password-policy-lab` entry point. Repository-only tests,
portfolio evidence, and browser captures are deliberately excluded from the
installable distribution and remain available in the source repository.

No project license is currently declared. Public source availability alone
does not grant permission to copy, modify, or redistribute the package.
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ make check

The package supports Python 3.11 or newer. `make check` runs Ruff, formatting,
strict mypy, exhaustive and independent mathematical oracles, real Flask
request tests, 100% combined line/branch coverage, and the committed-evidence
integrity check.
request tests, 100% combined line/branch coverage, the distribution
attestation, and the committed-evidence integrity check.

Start the pinned production WSGI server on loopback:

Expand All @@ -56,6 +56,48 @@ waitress-serve \

Then open `http://127.0.0.1:5000`.

## Reproducible distribution contract

![Measured distribution build, rebuild, and installed-smoke flow](docs/assets/distribution-contract.svg)

`make distribution-check` does not trust the migrated worktree's file modes or
an implicit setuptools file list. It snapshots exactly 15 stage-zero Git blobs,
materializes two normalized source trees, builds both with the pinned
`setuptools==83.0.0`, and validates exact archive inventories:

- the wheel has 17 regular members with fixed ZIP metadata and a complete,
canonical `RECORD`;
- the sdist has 23 regular files and six directories, with fixed modes, epoch,
owner fields, member order, and gzip header;
- a wheel rebuilt from the safely materialized canonical sdist is byte-for-byte
equal to the canonicalized wheel produced by each primary build;
- an offline `pip --target` install from an external working directory imports
package code and metadata from that target, finds both package resources, and
runs deterministic `inspect --length 20 --format json` twice without sampling.

![Real distribution attestation terminal output](docs/assets/distribution-check.png)

Run the attested path with:

```bash
make distribution-check
```

The raw [`distribution-check.txt`](docs/evidence/distribution-check.txt) and
canonical
[`distribution-attestation.json`](docs/evidence/distribution-attestation.json)
record the input digest, complete member-level SHA-256 inventory, canonical
archive hashes, rebuild equality, toolchain, smoke result, and negative claim
boundaries. `make build` remains a conventional backend build for local
inspection; its raw sdist contains environment-dependent metadata and is not
presented as the canonical release artifact.

The attestation is deliberately unofficial. It does not claim a license,
artifact signature, dependency integrity, cross-platform reproducibility, or
safety for arbitrary archives. The install smoke uses the current pinned
checker dependencies without resolving them; it is not a fresh, hash-locked
dependency environment.

## Architecture

![Source-derived package architecture](docs/assets/architecture.svg)
Expand Down Expand Up @@ -170,6 +212,11 @@ temporary files under this repository. On a minimal Linux image, Chromium's OS
runtime libraries still need to be supplied by that environment; the target
never invokes a privileged system-package install.

The capture contract waits for fonts and settled layout, preserves the declared
viewport during full-page screenshots, and pins Chromium to one raster thread.
That removes subpixel shadow races without replacing the real server-rendered
interface with a mockup; the exact launch argument is recorded in the manifest.

![Real project quality gate](docs/assets/quality-gate.png)

Evidence provenance stays next to the visuals:
Expand Down
Binary file added docs/assets/distribution-check.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 changes: 111 additions & 0 deletions docs/assets/distribution-contract.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/quality-gate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/assets/setup-workflow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/web-home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading