Skip to content
Merged
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ steps:
> [!NOTE]
> Default sources below assume the consuming workflow follows the Reponomics Dashboard template repository wiring for tokens and secrets. If you decide to use this action outside of that template, pass explicit `with:` input values.

For `collection-token`, use a [fine-grained personal access token](https://github.com/settings/personal-access-tokens/new?name=COLLECTION_TOKEN&description=Read%20repository%20data%20for%20Reponomics%20Dashboard&expires_in=366&administration=read) with repository `Administration: read` for the owner/repositories being collected. Choose **All repositories** for broad automatic discovery, or **Only selected repositories** for a narrower dashboard. If you choose selected repositories, keep the dashboard configuration within that token's repository access. It does not need Pages or Administration write permissions.
For `collection-token`, use a [fine-grained personal access token](https://github.com/settings/personal-access-tokens/new?name=COLLECTION_TOKEN&description=Read%20repository%20data%20for%20Reponomics%20Dashboard&expires_in=366&administration=read) with repository `Administration: read` for the owner/repositories listed under `collect.repositories`. Keep `collect.repositories` within that token's repository access, and use `publish.repositories` to choose the subset rendered in the README and Pages dashboards. It does not need Pages or Administration write permissions.

This action accepts one `collection-token`. Fine-grained personal access tokens are scoped to one GitHub resource owner, so a fine-grained token is the right fit only when the dashboard collects from one user or organization owner. If one dashboard must span multiple owners today, the current single-token fallback is a classic PAT with `repo` scope where the relevant organizations allow it.

Expand Down Expand Up @@ -175,7 +175,7 @@ gh run download RUN_ID --repo OWNER/REPO --name html-dashboard-plaintext --dir .
python3 -m http.server 8000 --directory .reponomics-dashboard
```

For encrypted dashboards, after unlock, use the dashboard `Export CSV` control to download a canonical ZIP of retained CSV files. Export delivery is browser-local: ciphertext is fetched from a published encrypted asset and decrypted in memory before download. The runtime verifies both encrypted-asset and decrypted-bundle digests before download. Plaintext export data is not uploaded back to GitHub by this path. Export scope is canonical retained history, including repos that are currently excluded from dashboard rendering.
For encrypted dashboards, after unlock, use the dashboard `Export CSV` control to download a canonical ZIP of retained CSV files. Export delivery is browser-local: ciphertext is fetched from a published encrypted asset and decrypted in memory before download. The runtime verifies both encrypted-asset and decrypted-bundle digests before download. Plaintext export data is not uploaded back to GitHub by this path. Export scope is canonical retained history, including repos that are not currently listed in `publish.repositories`.

See [CSV Export Architecture Guide](./docs/CSV_EXPORT.md) for implementation details, integrity model boundaries, and payload size-estimation formulas.

Expand Down
39 changes: 12 additions & 27 deletions dashboard_action/runtime/managed_docs/config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,33 +47,18 @@ auto_doctor_every_n_days: 0
# REPOSITORY SELECTION ------------------------------------------------------- *
# * * * * * * -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* * * * * *
#
# By default, Reponomics auto-discovers up to 200 eligible repositories visible
# to COLLECTION_TOKEN and fills the tracked set from newest to oldest by creation
# date.
# Reponomics only collects repositories you list explicitly.
#
# Use full owner/repo names for explicit entries.
# Use bare repo names for repositories owned by this dashboard repository's
# owner. Use owner/repo names when collecting from another owner.
#
max_repos: 200
collect:
repositories:
# - repo-name
# - other-owner/repo-name
#
# If non-empty, ONLY these and NO other repositories will be tracked.
include_only:
# - owner/repo-name
#
# Repositories that must always be tracked when accessible.
include:
# - owner/important-repo
#
# Repositories that must never be tracked automatically.
exclude:
# - owner/noisy-repo
#
# Fill remaining slots with other eligible repositories.
include_others: true
#
# Allow repositories created after the initial automatic-selection baseline to
# enter the automatic pool.
include_new: false
#
# Allow private repositories in the automatic pool when COLLECTION_TOKEN can see
# them.
include_private: true
# The published dashboard is intentionally narrow. It must be a subset of
# collect.repositories and can contain at most 8 repositories.
publish:
repositories:
# - repo-name
14 changes: 3 additions & 11 deletions dashboard_action/runtime/managed_docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,11 @@ The setup fields at the top of `config.yaml` represent important user preference

- `auto_doctor_every_n_days`: integer from `0` to `30`; `0` disables automatic doctor diagnostics. When set from `1` to `30`, collect-and-publish runs check the auto-doctor marker and run doctor when at least that many UTC days have elapsed since the last successful auto-doctor.

- `max_repos`: positive integer; caps how many repositories the dashboard tracks.
- `collect.repositories`: required list of repositories to collect. Entries may be bare repository names such as `api`, which resolve to the dashboard repository owner, or full names such as `other-owner/api`. Reponomics does not auto-discover or add repositories by default.

- `include_only`: list of `owner/repo` names; when non-empty, track only these repositories and ignore automatic discovery.
- `publish.repositories`: required list of repositories to render in the README and Pages dashboards. Every entry must also be present in `collect.repositories`, and the list can contain at most 8 repositories.

- `include`: list of `owner/repo` names; always include these repositories when the collection token can access them.

- `exclude`: list of `owner/repo` names; never include these repositories through automatic selection.

- `include_others`: boolean; when `true`, fill remaining `max_repos` slots from automatically discovered eligible repositories.

- `include_new`: boolean; when `true`, allow repositories created after the initial automatic-selection baseline into the automatic pool.

- `include_private`: boolean; when `true`, allow private repositories into the automatic pool when the collection token can access them.
`collect.repositories` is usually append-mostly: add a repository when you want Reponomics to start keeping history for it. To change what appears in dashboards, edit `publish.repositories`; removing a repository from `publish.repositories` does not stop collection.

## Constraints

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Common privacy, storage, export, and trust-boundary questions are answered in th

For release, dependency, vendored-asset, and generated-artifact verification materials, see [Provenance And Verification Materials](provenance.md).

`COLLECTION_TOKEN` is only for repository data collection, including GitHub traffic data. Create it as a [fine-grained personal access token](https://github.com/settings/personal-access-tokens/new?name=COLLECTION_TOKEN&description=Read%20repository%20data%20for%20Reponomics%20Dashboard&expires_in=366&administration=read), choose the owner whose repositories should be collected, and keep the prefilled repository permission `Administration: read`. Choose **All repositories** for broad automatic discovery, or **Only selected repositories** if you want to limit collection to specific repositories. If you choose selected repositories, keep `config.yaml` within that token's repository access. The setup workflow uses the repository-scoped `GITHUB_TOKEN` to commit workflow enablement changes, and the collect workflow uses the repository-scoped `GITHUB_TOKEN` with job-level `actions: write` for same-repository artifact cleanup after a successful upload, so the collection token does not need repository, Pages, Actions, or Administration write permissions. Ideally, we will have one, limited-scope token responsible for any queries outside of the dashboard repo, and all other operations will be done by the repo's own `GITHUB_TOKEN`. This minimizes the scope of the collection token, which for many users will have access to lots of repositories.
`COLLECTION_TOKEN` is only for repository data collection, including GitHub traffic data. Create it as a [fine-grained personal access token](https://github.com/settings/personal-access-tokens/new?name=COLLECTION_TOKEN&description=Read%20repository%20data%20for%20Reponomics%20Dashboard&expires_in=366&administration=read), choose the owner whose repositories should be collected, and keep the prefilled repository permission `Administration: read`. Reponomics only collects repositories listed in `collect.repositories`; keep that list within the token's repository access. Use `publish.repositories` to choose the subset, up to 8 repositories, rendered in the README and Pages dashboards. The setup workflow uses the repository-scoped `GITHUB_TOKEN` to commit workflow enablement changes, and the collect workflow uses the repository-scoped `GITHUB_TOKEN` with job-level `actions: write` for same-repository artifact cleanup after a successful upload, so the collection token does not need repository, Pages, Actions, or Administration write permissions. Ideally, we will have one, limited-scope token responsible for any queries outside of the dashboard repo, and all other operations will be done by the repo's own `GITHUB_TOKEN`. This minimizes the scope of the collection token, which for many users will have access to lots of repositories.

This template currently supports one collection credential. Fine-grained personal access tokens are scoped to one GitHub resource owner. If one dashboard needs to track repositories under multiple users or organizations, the fine-grained token flow is not the right fit for the current single-token setup. Use a classic PAT with `repo` scope where the relevant organizations allow it. Classic PATs are broader and can access repositories your GitHub account can access.

Expand Down
25 changes: 0 additions & 25 deletions dashboard_action/runtime/scripts/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,11 @@
secondary_retry_window as _http_secondary_retry_window,
)
from collect_modules.repositories import (
build_auto_candidates as _repositories_build_auto_candidates,
current_repository as _repositories_current_repository,
discover_repositories as _repositories_discover_repositories,
is_trackable_repo as _repositories_is_trackable_repo,
resolve_named_repos as _repositories_resolve_named_repos,
resolve_repositories as _repositories_resolve_repositories,
selection_state as _repositories_selection_state,
sort_auto_candidates as _repositories_sort_auto_candidates,
)
from collect_modules.runner import CollectionDependencies, run_collection
from collect_modules.status import (
Expand Down Expand Up @@ -270,30 +267,8 @@ def discover_repositories(headers: Headers) -> list[RepoMetadata]:


_is_trackable_repo = _repositories_is_trackable_repo
_selection_state = _repositories_selection_state
_current_repository = _repositories_current_repository
_resolve_named_repos = _repositories_resolve_named_repos
_sort_auto_candidates = _repositories_sort_auto_candidates


def _build_auto_candidates(
eligible: dict[str, RepoMetadata],
excluded: set[str],
selected_names: set[str],
current_repository: str,
include_private: bool,
include_new: bool,
auto_seeded_at: str,
) -> list[RepoMetadata]:
return _repositories_build_auto_candidates(
eligible,
excluded,
selected_names,
current_repository,
include_private,
include_new,
auto_seeded_at,
)


def resolve_repositories(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,16 @@

from collect_modules.repository_pages import discover_repositories
from collect_modules.repository_selection import (
build_auto_candidates,
current_repository,
is_trackable_repo,
resolve_named_repos,
resolve_repositories,
selection_state,
sort_auto_candidates,
)

__all__ = [
"build_auto_candidates",
"current_repository",
"discover_repositories",
"is_trackable_repo",
"resolve_named_repos",
"resolve_repositories",
"selection_state",
"sort_auto_candidates",
]
Loading