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
36 changes: 36 additions & 0 deletions .github/ISSUE_TEMPLATE/source-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Report a registry source
description: Report availability, security, maintenance, abuse, or rights concerns
title: "[Source report]: "
labels: [registry, source-report]
body:
- type: input
id: source_id
attributes:
label: Source ID
placeholder: org.example.public-books
validations:
required: true
- type: dropdown
id: category
attributes:
label: Category
options:
- Availability or compatibility
- Security or malicious behavior
- Maintainer or ownership
- Copyright or content rights
- Incorrect registry metadata
validations:
required: true
- type: textarea
id: evidence
attributes:
label: Evidence
description: Include dates, requests, responses, and public references. Do not post secrets.
validations:
required: true
- type: textarea
id: requested_action
attributes:
label: Requested action
description: Explain whether you are requesting correction, warning, suspension, or removal.
27 changes: 27 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/source-submission.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## ORSP source submission

- Source ID:
- Discovery URL:
- Source homepage:
- Source repository, if public:
- Maintainer GitHub account(s):

## Content declaration

- [ ] The source contains only original, public-domain, or properly licensed content.
- [ ] I operate this source or am authorized by its operator to submit it.
- [ ] A public reporting or contact path is available where practical.

## Compatibility and safety

- [ ] The source implements discovery, search, detail, catalog, and content.
- [ ] The manifest filename exactly matches the discovery source ID.
- [ ] `testQuery` returns at least one readable book and chapter.
- [ ] The source does not return credentials, cookies, executable rules, or private infrastructure details.
- [ ] I ran `python scripts/registry_tool.py validate`.
- [ ] I ran `python scripts/registry_tool.py build --check`.
- [ ] I ran `python scripts/registry_tool.py check-source registry/sources/<source-id>.json`.

## Additional context

Describe licensing, hosting, regional availability, rate limits, or other facts reviewers should know.
41 changes: 41 additions & 0 deletions .github/workflows/registry-health.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Check community registry health

on:
workflow_dispatch:
schedule:
- cron: '23 3 * * *'

permissions:
contents: read

jobs:
health:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install registry validator
run: python -m pip install --disable-pip-version-check jsonschema
- name: Validate registry before network access
run: |
python scripts/registry_tool.py validate
python scripts/registry_tool.py build --check
- name: Check public sources
id: health
continue-on-error: true
run: >-
python scripts/registry_tool.py check-all
--status-output registry-health.json
- name: Upload health report
if: always()
uses: actions/upload-artifact@v4
with:
name: orsp-registry-health
path: registry-health.json
if-no-files-found: error
retention-days: 30
- name: Fail after preserving the report
if: steps.health.outcome == 'failure'
run: exit 1
62 changes: 62 additions & 0 deletions .github/workflows/registry-pr-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Check submitted registry sources

on:
pull_request:
paths:
- 'registry/sources/**'

permissions:
contents: read

jobs:
network-check:
runs-on: ubuntu-latest
steps:
- name: Check out trusted validator from the base revision
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.sha }}
path: validator
persist-credentials: false
- name: Check out submitted manifests without credentials
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
path: submission
persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install trusted validator dependencies
run: python -m pip install --disable-pip-version-check jsonschema
- name: Identify submitted source manifests
run: |
: > submitted-sources.txt
shopt -s dotglob nullglob
for path in submission/registry/sources/*; do
file="${path#submission/}"
if [ "$file" = "registry/sources/.gitkeep" ]; then
continue
fi
if [ -L "$path" ] || [ ! -f "$path" ]; then
echo "Registry source must be a regular file: $file" >&2
exit 1
fi
if [[ ! "$file" =~ ^registry/sources/[A-Za-z0-9._-]+\.json$ ]]; then
echo "Invalid registry source path: $file" >&2
exit 1
fi
if [ ! -f "validator/$file" ] || ! cmp -s "validator/$file" "$path"; then
echo "$file" >> submitted-sources.txt
fi
done
if [ ! -s submitted-sources.txt ]; then
echo "No added or modified source manifest requires a network check."
fi
- name: Run trusted network checks without repository credentials
run: |
while IFS= read -r file; do
[ -z "$file" ] && continue
python validator/scripts/registry_tool.py check-source "submission/$file"
done < submitted-sources.txt
27 changes: 17 additions & 10 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,22 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install contract validators
run: >-
python -m pip install --disable-pip-version-check
jsonschema pyyaml openapi-spec-validator
- name: Check Dart formatting
run: dart format --output=none --set-exit-if-changed examples/dart_server.dart
- name: Analyze reference server
run: dart analyze examples/dart_server.dart
- name: Validate JSON documents
run: >-
dart format --output=none --set-exit-if-changed
examples/dart_server.dart tool/conformance_test.dart
- name: Analyze Dart implementation
run: dart analyze examples/dart_server.dart tool/conformance_test.dart
- name: Validate schemas, examples, and OpenAPI
run: python scripts/validate_contracts.py
- name: Validate community registry manifests
run: |
python -m json.tool schemas/discovery.schema.json > /dev/null
python -m json.tool examples/open-reading-source.json > /dev/null
- name: Validate OpenAPI YAML syntax
run: |
python -m pip install --disable-pip-version-check pyyaml
python -c "import pathlib, yaml; yaml.safe_load(pathlib.Path('openapi.yaml').read_text())"
python scripts/registry_tool.py validate
python scripts/registry_tool.py build --check
python scripts/test_registry_tool.py
- name: Run core conformance tests
run: dart run tool/conformance_test.dart
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
.dart_tool/
.omx/
__pycache__/
*.pyc
.idea/
.vscode/
build/
Expand Down
67 changes: 50 additions & 17 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,68 @@

Thank you for helping improve Open Reading Source Protocol.

Read [GOVERNANCE.md](GOVERNANCE.md) before proposing a protocol change. ORSP
optimizes for interoperability across independently developed readers and
sources, so a useful feature is not automatically suitable for the core.

## Implementation feedback

Implementation feedback is especially valuable. Please include:

1. whether you implemented a source, reader, adapter, registry, or test tool;
2. the language and framework used;
3. the protocol version and capabilities tested;
4. behavior that was ambiguous or differed between implementations;
5. a minimal request and response example where possible.

## Proposing a protocol change

Open an issue describing:
Open a protocol issue describing:

1. the source-developer or reader problem;
2. why the current protocol cannot solve it;
3. the proposed request or response shape;
4. backward-compatibility impact;
5. security, privacy, and copyright considerations.
2. why the current protocol or a namespaced extension cannot solve it;
3. the proposed request, response, and capability shape;
4. backward- and forward-compatibility impact;
5. security, privacy, accessibility, and copyright considerations;
6. migration and deprecation behavior;
7. implementation and test evidence.

Protocol changes should update the specification, OpenAPI document, relevant
JSON Schemas, and at least one example.
Protocol changes must update the specification, OpenAPI document, relevant
JSON Schemas, examples, and conformance tests in the same pull request.

## Compatibility
## Compatibility rules

- Additive optional fields can usually remain within the current major version.
- Changing required fields, endpoint meaning, or response semantics requires a
new major protocol version.
- Implementations must ignore unknown discovery fields unless a future
capability explicitly says otherwise.
- Minor releases may add optional fields and optional behavior only.
- Existing field and endpoint meanings cannot change within a major version.
- Implementations must ignore unknown JSON object members at every nesting
level.
- Implementations must ignore unknown optional capability tokens.
- Extension capabilities use `reverse.domain:name` and cannot use the reserved
`orsp` namespace.
- Missing and `null` are distinct; null is invalid unless explicitly declared.
- Incompatible changes require a new major protocol version and migration
documentation.

## Local checks

```bash
dart format --output=none --set-exit-if-changed examples/dart_server.dart
dart analyze examples/dart_server.dart
python -m json.tool schemas/discovery.schema.json > /dev/null
python -m json.tool examples/open-reading-source.json > /dev/null
dart format --output=none --set-exit-if-changed \
examples/dart_server.dart tool/conformance_test.dart
dart analyze examples/dart_server.dart tool/conformance_test.dart
dart run tool/conformance_test.dart
python -m pip install jsonschema pyyaml openapi-spec-validator
python scripts/validate_contracts.py
python scripts/registry_tool.py validate
python scripts/registry_tool.py build --check
python scripts/test_registry_tool.py
```

The CI workflow runs the same checks. JSON or YAML syntax validation alone is
not considered protocol conformance.

Community source submissions follow [registry/README.md](registry/README.md)
and should use the source-submission pull-request template. A registry listing
is a separate decision from changing the ORSP protocol.

By contributing, you agree that your contribution is licensed under the MIT
License used by this repository.
76 changes: 76 additions & 0 deletions ECOSYSTEM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# ORSP Ecosystem Architecture

ORSP separates three concerns so the community can grow without making readers
unsafe or the wire protocol unstable.

## 1. Wire protocol

The ORSP core is the HTTP contract implemented by readers and sources. It
defines data and behavior, not scraping programs. A reader should be able to
connect to any conforming source without source-specific code.

## 2. Server-side adapters

An adapter translates an existing authorized content service into ORSP. It may
use HTML parsing, vendor APIs, databases, or other source-specific logic on the
server side. Credentials and executable rules remain under the adapter
operator's control and are never sent to readers.

Future adapter SDKs should provide:

- typed ORSP response models;
- request validation and pagination helpers;
- caching, rate limiting, and safe upstream-fetch defaults;
- HTML sanitization utilities;
- conformance-test integration;
- migration guides for existing book-source formats.

Adapter compatibility is separate from the ORSP wire version. A legacy format
can evolve or disappear without forcing every reader to change.

## 3. Federated registries

A registry helps users discover sources. It is not the protocol authority and
does not need to be unique. Readers may subscribe to multiple community,
regional, organizational, or private registries.

A future registry companion specification should describe signed or
integrity-protected entries containing at least:

- source ID and discovery URL;
- operator and maintainer information;
- supported languages and capabilities;
- last successful conformance result and test-suite version;
- health-check time without exposing private infrastructure;
- content-rights declaration, reporting contact, and removal status;
- optional reputation and community moderation metadata.

Registry entries must not duplicate the complete discovery document as a new
source of truth. Readers should fetch discovery from the source and compare the
stable source ID.

This repository now contains an initial PR-based implementation under
[`registry/`](registry/README.md). It is intentionally a community registry
prototype rather than the final companion specification. Operational evidence
from this implementation should guide the federated format.

## Trust model

Protocol conformance proves interoperability, not legality, content quality, or
operator trustworthiness. Registries should present these as separate signals.
A source can be technically conforming and still be unsuitable for a registry.

Readers should clearly show source identity, origin, permissions, security
warnings, and removal information. Private-network sources should require an
explicit client policy.

## Roadmap

1. Stabilize ORSP 1.0 and publish a reusable core conformance kit.
2. Build adapter SDKs in at least two server ecosystems.
3. Test multiple independent readers and sources and publish a compatibility
matrix.
4. Draft a federated registry companion specification using real operational
experience.
5. Standardize additional capabilities only after extension implementations
demonstrate compatible semantics.
Loading
Loading