patent-checker 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- patent_checker-0.5.0/.dockerignore +39 -0
- patent_checker-0.5.0/.env.example +68 -0
- patent_checker-0.5.0/.github/workflows/ci.yml +112 -0
- patent_checker-0.5.0/.github/workflows/release.yml +163 -0
- patent_checker-0.5.0/.gitignore +231 -0
- patent_checker-0.5.0/Dockerfile +90 -0
- patent_checker-0.5.0/LICENSE +201 -0
- patent_checker-0.5.0/PKG-INFO +529 -0
- patent_checker-0.5.0/README.md +503 -0
- patent_checker-0.5.0/README_ja.md +314 -0
- patent_checker-0.5.0/compose.yaml +75 -0
- patent_checker-0.5.0/install.ps1 +111 -0
- patent_checker-0.5.0/install.sh +122 -0
- patent_checker-0.5.0/patent_checker/__init__.py +10 -0
- patent_checker-0.5.0/patent_checker/cache.py +863 -0
- patent_checker-0.5.0/patent_checker/claimref.py +88 -0
- patent_checker-0.5.0/patent_checker/cleanup.py +522 -0
- patent_checker-0.5.0/patent_checker/cli/__init__.py +1 -0
- patent_checker-0.5.0/patent_checker/cli/main.py +868 -0
- patent_checker-0.5.0/patent_checker/config.py +300 -0
- patent_checker-0.5.0/patent_checker/consent.py +191 -0
- patent_checker-0.5.0/patent_checker/gp/__init__.py +1 -0
- patent_checker-0.5.0/patent_checker/gp/fetch.py +155 -0
- patent_checker-0.5.0/patent_checker/gp/parse.py +268 -0
- patent_checker-0.5.0/patent_checker/installer/__init__.py +457 -0
- patent_checker-0.5.0/patent_checker/installer/agents.py +614 -0
- patent_checker-0.5.0/patent_checker/installer/errors.py +10 -0
- patent_checker-0.5.0/patent_checker/installer/skill.py +189 -0
- patent_checker-0.5.0/patent_checker/installer/token.py +121 -0
- patent_checker-0.5.0/patent_checker/installer/writers.py +426 -0
- patent_checker-0.5.0/patent_checker/models.py +22 -0
- patent_checker-0.5.0/patent_checker/net.py +63 -0
- patent_checker-0.5.0/patent_checker/notices/consent-notice.en.md +48 -0
- patent_checker-0.5.0/patent_checker/notices/consent-notice.ja.md +44 -0
- patent_checker-0.5.0/patent_checker/notices/operator-notice.en.md +58 -0
- patent_checker-0.5.0/patent_checker/notices/operator-notice.ja.md +57 -0
- patent_checker-0.5.0/patent_checker/ops/__init__.py +1 -0
- patent_checker-0.5.0/patent_checker/ops/client.py +356 -0
- patent_checker-0.5.0/patent_checker/ops/parse.py +606 -0
- patent_checker-0.5.0/patent_checker/pubnum.py +130 -0
- patent_checker-0.5.0/patent_checker/server/__init__.py +1 -0
- patent_checker-0.5.0/patent_checker/server/app.py +384 -0
- patent_checker-0.5.0/patent_checker/server/settings.py +359 -0
- patent_checker-0.5.0/patent_checker/server/tools.py +507 -0
- patent_checker-0.5.0/patent_checker/service.py +546 -0
- patent_checker-0.5.0/patent_checker/utils.py +450 -0
- patent_checker-0.5.0/pyproject.toml +57 -0
- patent_checker-0.5.0/secrets/README.md +86 -0
- patent_checker-0.5.0/skills/patent-checker/SKILL.md +293 -0
- patent_checker-0.5.0/skills/patent-checker/references/consent-notice.en.md +48 -0
- patent_checker-0.5.0/skills/patent-checker/references/consent-notice.ja.md +44 -0
- patent_checker-0.5.0/skills/patent-checker/references/legal-status-codes.md +82 -0
- patent_checker-0.5.0/skills/patent-checker/references/report-template.md +91 -0
- patent_checker-0.5.0/tests/installer_fixtures/claude_mcp.json +11 -0
- patent_checker-0.5.0/tests/installer_fixtures/codex_config.toml +7 -0
- patent_checker-0.5.0/tests/installer_fixtures/codex_config_existing.toml +5 -0
- patent_checker-0.5.0/tests/installer_fixtures/copilot_mcp-config.json +11 -0
- patent_checker-0.5.0/tests/installer_fixtures/cursor_mcp.json +14 -0
- patent_checker-0.5.0/tests/installer_fixtures/gemini_settings.json +12 -0
- patent_checker-0.5.0/tests/installer_fixtures/opencode.json +13 -0
- patent_checker-0.5.0/tests/installer_fixtures/opencode.jsonc +9 -0
- patent_checker-0.5.0/tests/test_cache.py +1221 -0
- patent_checker-0.5.0/tests/test_claimref.py +56 -0
- patent_checker-0.5.0/tests/test_cleanup.py +570 -0
- patent_checker-0.5.0/tests/test_cli.py +1494 -0
- patent_checker-0.5.0/tests/test_config.py +439 -0
- patent_checker-0.5.0/tests/test_consent.py +185 -0
- patent_checker-0.5.0/tests/test_gp_fetch.py +189 -0
- patent_checker-0.5.0/tests/test_gp_parse.py +335 -0
- patent_checker-0.5.0/tests/test_installer.py +2082 -0
- patent_checker-0.5.0/tests/test_net.py +122 -0
- patent_checker-0.5.0/tests/test_ops_client.py +434 -0
- patent_checker-0.5.0/tests/test_ops_parse.py +464 -0
- patent_checker-0.5.0/tests/test_packaging.py +97 -0
- patent_checker-0.5.0/tests/test_pubnum.py +267 -0
- patent_checker-0.5.0/tests/test_server_auth.py +284 -0
- patent_checker-0.5.0/tests/test_server_settings.py +521 -0
- patent_checker-0.5.0/tests/test_server_tools.py +1100 -0
- patent_checker-0.5.0/tests/test_service.py +982 -0
- patent_checker-0.5.0/tests/test_skill_assets.py +216 -0
- patent_checker-0.5.0/tests/test_utils.py +472 -0
- patent_checker-0.5.0/tools/check.sh +8 -0
- patent_checker-0.5.0/tools/container_smoke.sh +220 -0
- patent_checker-0.5.0/tools/release_check.sh +134 -0
- patent_checker-0.5.0/tools/smoke.py +89 -0
- patent_checker-0.5.0/uv.lock +1663 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Build-context exclusions.
|
|
2
|
+
#
|
|
3
|
+
# What must NOT be listed here, because hatchling needs it to build the
|
|
4
|
+
# wheel the image installs: README.md, LICENSE, pyproject.toml, uv.lock,
|
|
5
|
+
# patent_checker/ and skills/.
|
|
6
|
+
|
|
7
|
+
# Recipes and VCS metadata: BuildKit receives the Dockerfile out of band, and
|
|
8
|
+
# a copied .git would both bloat the context and bake history into a layer.
|
|
9
|
+
.git
|
|
10
|
+
.gitignore
|
|
11
|
+
.dockerignore
|
|
12
|
+
Dockerfile
|
|
13
|
+
compose.yaml
|
|
14
|
+
|
|
15
|
+
# Local state and credentials must never reach a layer, not even a discarded
|
|
16
|
+
# builder one.
|
|
17
|
+
.venv
|
|
18
|
+
.env
|
|
19
|
+
.env.*
|
|
20
|
+
secrets/
|
|
21
|
+
.patent-checker/
|
|
22
|
+
|
|
23
|
+
# Developer-only material: not part of the shipped package.
|
|
24
|
+
PROJECT.md
|
|
25
|
+
開発資料/
|
|
26
|
+
tests/
|
|
27
|
+
tools/
|
|
28
|
+
.github/
|
|
29
|
+
install.sh
|
|
30
|
+
install.ps1
|
|
31
|
+
|
|
32
|
+
# Caches and build outputs: host artefacts, rebuilt inside the image anyway.
|
|
33
|
+
.pytest_cache
|
|
34
|
+
.ruff_cache
|
|
35
|
+
__pycache__
|
|
36
|
+
**/__pycache__
|
|
37
|
+
dist/
|
|
38
|
+
build/
|
|
39
|
+
*.egg-info
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Copy this file to .env and fill in your own credentials.
|
|
2
|
+
# Never commit .env; secrets must not appear in the repository, logs, or docs.
|
|
3
|
+
|
|
4
|
+
# EPO OPS consumer credentials (register at https://developers.epo.org/,
|
|
5
|
+
# then My Apps -> add an app to obtain the key/secret pair).
|
|
6
|
+
PATENT_CHECKER_OPS_KEY=
|
|
7
|
+
PATENT_CHECKER_OPS_SECRET=
|
|
8
|
+
|
|
9
|
+
# Optional: data directory (search cache, request log; the CLI also keeps
|
|
10
|
+
# its exploration artifacts here). Defaults to ./.patent-checker for the CLI
|
|
11
|
+
# and to the per-user data directory for the MCP server. When set, the
|
|
12
|
+
# shared document cache is placed under it too (<dir>/cache) unless
|
|
13
|
+
# PATENT_CHECKER_CACHE_DIR is also set.
|
|
14
|
+
# PATENT_CHECKER_DATA_DIR=
|
|
15
|
+
|
|
16
|
+
# Optional: shared document cache (biblio, claims, legal status, family,
|
|
17
|
+
# Google Patents pages), reused across projects and by the CLI and the
|
|
18
|
+
# server alike. Defaults to <per-user data dir>/cache, e.g.
|
|
19
|
+
# ~/.local/share/patent-checker/cache (Linux/macOS) or
|
|
20
|
+
# %LOCALAPPDATA%\patent-checker\cache (Windows).
|
|
21
|
+
# PATENT_CHECKER_CACHE_DIR=
|
|
22
|
+
|
|
23
|
+
# Optional: per-kind cache expiry overrides, comma-separated kind=ttl.
|
|
24
|
+
# Kinds: biblio, claims, legal, family, gp, search, searchbib. A ttl is
|
|
25
|
+
# <n>d (days), <n>h (hours) or 0 (never expires). Defaults: biblio=90d,
|
|
26
|
+
# claims=0, legal=7d, family=30d, gp=0, search=1d, searchbib=1d. An
|
|
27
|
+
# invalid value is a configuration error (no silent fallback).
|
|
28
|
+
# PATENT_CHECKER_CACHE_TTL=legal=3d,family=14d
|
|
29
|
+
|
|
30
|
+
# MCP server settings (patent-checker serve). The server refuses to start
|
|
31
|
+
# until the operator notice has been read and acknowledged: run
|
|
32
|
+
# `patent-checker serve --show-operator-notice` (add `--lang ja` for the
|
|
33
|
+
# Japanese version), then set this to the version number shown there
|
|
34
|
+
# (currently 1.0).
|
|
35
|
+
PATENT_CHECKER_OPERATOR_CONSENT=
|
|
36
|
+
|
|
37
|
+
# Note for docker compose users: compose.yaml does not read this file for
|
|
38
|
+
# the container. It takes the OPS credentials and the bearer token from the
|
|
39
|
+
# files under secrets/ (see secrets/README.md) and reads only
|
|
40
|
+
# PATENT_CHECKER_OPERATOR_CONSENT (and optionally PATENT_CHECKER_IMAGE,
|
|
41
|
+
# PATENT_CHECKER_PORT, PATENT_CHECKER_LOG_LEVEL) from a .env next to it.
|
|
42
|
+
|
|
43
|
+
# Bearer token required by the http transport (not used by stdio). Supply
|
|
44
|
+
# either the value directly or a file path via the _FILE variant; exactly
|
|
45
|
+
# one of the two may be set. Generate a token with:
|
|
46
|
+
# python -c "import secrets; print(secrets.token_urlsafe(32))"
|
|
47
|
+
PATENT_CHECKER_SERVER_TOKEN=
|
|
48
|
+
# PATENT_CHECKER_SERVER_TOKEN_FILE=
|
|
49
|
+
|
|
50
|
+
# Optional: interface/port to bind (http transport). Defaults to
|
|
51
|
+
# 127.0.0.1:8642.
|
|
52
|
+
# PATENT_CHECKER_SERVER_HOST=
|
|
53
|
+
# PATENT_CHECKER_SERVER_PORT=8642
|
|
54
|
+
|
|
55
|
+
# Required when PATENT_CHECKER_SERVER_HOST is not a loopback address:
|
|
56
|
+
# comma-separated hostnames clients will use in the Host header. TLS must
|
|
57
|
+
# then be provided by a reverse proxy in front of the server.
|
|
58
|
+
# PATENT_CHECKER_SERVER_ALLOWED_HOSTS=
|
|
59
|
+
|
|
60
|
+
# Optional: server log level (debug, info, warning, error; default info).
|
|
61
|
+
# All server logs, including the access log, go to standard error.
|
|
62
|
+
# PATENT_CHECKER_LOG_LEVEL=info
|
|
63
|
+
|
|
64
|
+
# Optional: rate limit on incoming MCP requests (a guard against runaway
|
|
65
|
+
# agent loops; upstream OPS/Google Patents pacing is handled separately).
|
|
66
|
+
# Defaults to 5 requests/second with a burst of 10.
|
|
67
|
+
# PATENT_CHECKER_SERVER_RPS=5
|
|
68
|
+
# PATENT_CHECKER_SERVER_BURST=10
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# CI for patent-checker.
|
|
2
|
+
#
|
|
3
|
+
# "check" runs lint, format check and the unit tests on Linux, "check-macos"
|
|
4
|
+
# and "check-windows" run the unit tests on the other two desktop platforms,
|
|
5
|
+
# and "container" builds the Docker image and drives it through
|
|
6
|
+
# tools/container_smoke.sh (docker compose up, /health, bearer token,
|
|
7
|
+
# operator-notice gate). Unit tests never touch the network; the container
|
|
8
|
+
# smoke test starts the server in degraded mode (no EPO OPS credentials)
|
|
9
|
+
# with a throw-away bearer token that is never printed.
|
|
10
|
+
name: CI
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
branches:
|
|
15
|
+
- main
|
|
16
|
+
- "v*"
|
|
17
|
+
pull_request:
|
|
18
|
+
|
|
19
|
+
concurrency:
|
|
20
|
+
group: ci-${{ github.ref }}
|
|
21
|
+
cancel-in-progress: true
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
check:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
timeout-minutes: 20
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v7
|
|
32
|
+
|
|
33
|
+
- name: Install uv
|
|
34
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
35
|
+
with:
|
|
36
|
+
enable-cache: true
|
|
37
|
+
python-version: "3.12"
|
|
38
|
+
|
|
39
|
+
- name: Install dependencies
|
|
40
|
+
run: uv sync --locked
|
|
41
|
+
|
|
42
|
+
- name: Lint, format check and unit tests
|
|
43
|
+
run: tools/check.sh
|
|
44
|
+
|
|
45
|
+
- name: Bootstrap script dry run
|
|
46
|
+
run: sh install.sh --dry-run
|
|
47
|
+
|
|
48
|
+
check-macos:
|
|
49
|
+
runs-on: macos-latest
|
|
50
|
+
timeout-minutes: 20
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v7
|
|
53
|
+
|
|
54
|
+
- name: Install uv
|
|
55
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
56
|
+
with:
|
|
57
|
+
enable-cache: true
|
|
58
|
+
python-version: "3.12"
|
|
59
|
+
|
|
60
|
+
- name: Install dependencies
|
|
61
|
+
run: uv sync --locked
|
|
62
|
+
|
|
63
|
+
- name: Unit tests
|
|
64
|
+
run: uv run pytest -q
|
|
65
|
+
|
|
66
|
+
- name: Bootstrap script dry run
|
|
67
|
+
run: sh install.sh --dry-run
|
|
68
|
+
|
|
69
|
+
check-windows:
|
|
70
|
+
runs-on: windows-latest
|
|
71
|
+
timeout-minutes: 30
|
|
72
|
+
steps:
|
|
73
|
+
- uses: actions/checkout@v7
|
|
74
|
+
|
|
75
|
+
- name: Install uv
|
|
76
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
77
|
+
with:
|
|
78
|
+
enable-cache: true
|
|
79
|
+
python-version: "3.12"
|
|
80
|
+
|
|
81
|
+
- name: Install dependencies
|
|
82
|
+
run: uv sync --locked
|
|
83
|
+
|
|
84
|
+
- name: Unit tests
|
|
85
|
+
run: uv run pytest -q
|
|
86
|
+
|
|
87
|
+
- name: Bootstrap script dry run
|
|
88
|
+
run: pwsh -NoProfile -File install.ps1 -DryRun
|
|
89
|
+
|
|
90
|
+
container:
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
timeout-minutes: 30
|
|
93
|
+
steps:
|
|
94
|
+
- uses: actions/checkout@v7
|
|
95
|
+
|
|
96
|
+
- name: Set up Docker Buildx
|
|
97
|
+
uses: docker/setup-buildx-action@v4
|
|
98
|
+
|
|
99
|
+
- name: Build the image
|
|
100
|
+
uses: docker/build-push-action@v7
|
|
101
|
+
with:
|
|
102
|
+
context: .
|
|
103
|
+
load: true
|
|
104
|
+
push: false
|
|
105
|
+
tags: patent-checker:ci
|
|
106
|
+
cache-from: type=gha
|
|
107
|
+
cache-to: type=gha,mode=max
|
|
108
|
+
|
|
109
|
+
- name: Smoke-test the image with docker compose
|
|
110
|
+
env:
|
|
111
|
+
PATENT_CHECKER_IMAGE: patent-checker:ci
|
|
112
|
+
run: tools/container_smoke.sh
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Release workflow for patent-checker.
|
|
2
|
+
#
|
|
3
|
+
# Runs when a version tag (v*) is pushed: verifies that the tag matches the
|
|
4
|
+
# version declared in pyproject.toml, builds the multi-architecture image and
|
|
5
|
+
# pushes it to GHCR (always) and to Docker Hub (only when the Docker Hub
|
|
6
|
+
# variables and token are configured), then builds the wheel and sdist and
|
|
7
|
+
# publishes them to PyPI through trusted publishing (OIDC), so no API token
|
|
8
|
+
# is stored in the repository.
|
|
9
|
+
#
|
|
10
|
+
# Every push to a version branch (v*) runs the same workflow as a dry run:
|
|
11
|
+
# the image is built for both architectures but not pushed, and the
|
|
12
|
+
# distributions are built but not uploaded. Once the workflow exists on the
|
|
13
|
+
# default branch it can also be started by hand (workflow_dispatch), with
|
|
14
|
+
# `publish` deciding between a dry run and a real publication.
|
|
15
|
+
name: Release
|
|
16
|
+
|
|
17
|
+
on:
|
|
18
|
+
push:
|
|
19
|
+
tags:
|
|
20
|
+
- "v*"
|
|
21
|
+
branches:
|
|
22
|
+
- "v*"
|
|
23
|
+
workflow_dispatch:
|
|
24
|
+
inputs:
|
|
25
|
+
publish:
|
|
26
|
+
description: "Push the image and publish to PyPI (otherwise a dry run)"
|
|
27
|
+
type: boolean
|
|
28
|
+
default: false
|
|
29
|
+
|
|
30
|
+
permissions:
|
|
31
|
+
contents: read
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
verify:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
timeout-minutes: 10
|
|
37
|
+
outputs:
|
|
38
|
+
publish: ${{ steps.decide.outputs.publish }}
|
|
39
|
+
images: ${{ steps.decide.outputs.images }}
|
|
40
|
+
dockerhub: ${{ steps.decide.outputs.dockerhub }}
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v7
|
|
43
|
+
|
|
44
|
+
- name: Verify the tag matches the declared version
|
|
45
|
+
if: github.ref_type == 'tag'
|
|
46
|
+
run: |
|
|
47
|
+
declared="$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")"
|
|
48
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
49
|
+
if [ "$declared" != "$tag" ]; then
|
|
50
|
+
echo "tag ${GITHUB_REF_NAME} does not match declared version ${declared}" >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
echo "OK: ${GITHUB_REF_NAME} matches declared version ${declared}"
|
|
54
|
+
|
|
55
|
+
- name: Decide what to publish and where
|
|
56
|
+
id: decide
|
|
57
|
+
env:
|
|
58
|
+
REF_TYPE: ${{ github.ref_type }}
|
|
59
|
+
PUBLISH_INPUT: ${{ inputs.publish }}
|
|
60
|
+
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
|
|
61
|
+
DOCKERHUB_NAMESPACE: ${{ vars.DOCKERHUB_NAMESPACE }}
|
|
62
|
+
DOCKERHUB_TOKEN_SET: ${{ secrets.DOCKERHUB_TOKEN != '' }}
|
|
63
|
+
run: |
|
|
64
|
+
if [ "$REF_TYPE" = "tag" ] || [ "$PUBLISH_INPUT" = "true" ]; then
|
|
65
|
+
publish=true
|
|
66
|
+
else
|
|
67
|
+
publish=false
|
|
68
|
+
fi
|
|
69
|
+
images="ghcr.io/${GITHUB_REPOSITORY}"
|
|
70
|
+
dockerhub=false
|
|
71
|
+
if [ -n "$DOCKERHUB_USERNAME" ] && [ -n "$DOCKERHUB_NAMESPACE" ] && [ "$DOCKERHUB_TOKEN_SET" = "true" ]; then
|
|
72
|
+
dockerhub=true
|
|
73
|
+
images="$(printf '%s\n%s' "$images" "docker.io/${DOCKERHUB_NAMESPACE}/patent-checker")"
|
|
74
|
+
else
|
|
75
|
+
echo "Docker Hub is not configured (DOCKERHUB_USERNAME / DOCKERHUB_NAMESPACE / DOCKERHUB_TOKEN); pushing to GHCR only"
|
|
76
|
+
fi
|
|
77
|
+
{
|
|
78
|
+
echo "publish=${publish}"
|
|
79
|
+
echo "dockerhub=${dockerhub}"
|
|
80
|
+
echo "images<<EOF"
|
|
81
|
+
echo "${images}"
|
|
82
|
+
echo "EOF"
|
|
83
|
+
} >> "$GITHUB_OUTPUT"
|
|
84
|
+
echo "publish=${publish} dockerhub=${dockerhub}"
|
|
85
|
+
|
|
86
|
+
image:
|
|
87
|
+
needs: verify
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
timeout-minutes: 60
|
|
90
|
+
permissions:
|
|
91
|
+
contents: read
|
|
92
|
+
packages: write
|
|
93
|
+
steps:
|
|
94
|
+
- uses: actions/checkout@v7
|
|
95
|
+
|
|
96
|
+
- name: Set up QEMU
|
|
97
|
+
uses: docker/setup-qemu-action@v4
|
|
98
|
+
|
|
99
|
+
- name: Set up Docker Buildx
|
|
100
|
+
uses: docker/setup-buildx-action@v4
|
|
101
|
+
|
|
102
|
+
- name: Log in to GHCR
|
|
103
|
+
if: needs.verify.outputs.publish == 'true'
|
|
104
|
+
uses: docker/login-action@v4
|
|
105
|
+
with:
|
|
106
|
+
registry: ghcr.io
|
|
107
|
+
username: ${{ github.actor }}
|
|
108
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
109
|
+
|
|
110
|
+
- name: Log in to Docker Hub
|
|
111
|
+
if: needs.verify.outputs.publish == 'true' && needs.verify.outputs.dockerhub == 'true'
|
|
112
|
+
uses: docker/login-action@v4
|
|
113
|
+
with:
|
|
114
|
+
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
115
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
116
|
+
|
|
117
|
+
- name: Image metadata
|
|
118
|
+
id: meta
|
|
119
|
+
uses: docker/metadata-action@v6
|
|
120
|
+
with:
|
|
121
|
+
images: ${{ needs.verify.outputs.images }}
|
|
122
|
+
tags: |
|
|
123
|
+
type=semver,pattern={{version}}
|
|
124
|
+
type=semver,pattern={{major}}.{{minor}}
|
|
125
|
+
type=sha
|
|
126
|
+
type=raw,value=dry-run,enable=${{ github.ref_type != 'tag' }}
|
|
127
|
+
labels: |
|
|
128
|
+
org.opencontainers.image.title=patent-checker
|
|
129
|
+
org.opencontainers.image.licenses=Apache-2.0
|
|
130
|
+
|
|
131
|
+
- name: Build (and push) the multi-architecture image
|
|
132
|
+
uses: docker/build-push-action@v7
|
|
133
|
+
with:
|
|
134
|
+
context: .
|
|
135
|
+
platforms: linux/amd64,linux/arm64
|
|
136
|
+
push: ${{ needs.verify.outputs.publish == 'true' }}
|
|
137
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
138
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
139
|
+
cache-from: type=gha
|
|
140
|
+
cache-to: type=gha,mode=max
|
|
141
|
+
|
|
142
|
+
pypi:
|
|
143
|
+
needs: [verify, image]
|
|
144
|
+
runs-on: ubuntu-latest
|
|
145
|
+
timeout-minutes: 15
|
|
146
|
+
environment: pypi
|
|
147
|
+
permissions:
|
|
148
|
+
contents: read
|
|
149
|
+
id-token: write
|
|
150
|
+
steps:
|
|
151
|
+
- uses: actions/checkout@v7
|
|
152
|
+
|
|
153
|
+
- name: Install uv
|
|
154
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
155
|
+
with:
|
|
156
|
+
python-version: "3.12"
|
|
157
|
+
|
|
158
|
+
- name: Build wheel and sdist
|
|
159
|
+
run: uv build
|
|
160
|
+
|
|
161
|
+
- name: Publish to PyPI
|
|
162
|
+
if: needs.verify.outputs.publish == 'true'
|
|
163
|
+
run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
*.lcov
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
# Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# UV
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# uv.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
# poetry.lock
|
|
110
|
+
# poetry.toml
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
115
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
116
|
+
# pdm.lock
|
|
117
|
+
# pdm.toml
|
|
118
|
+
.pdm-python
|
|
119
|
+
.pdm-build/
|
|
120
|
+
|
|
121
|
+
# pixi
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
123
|
+
# pixi.lock
|
|
124
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
125
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
126
|
+
.pixi/*
|
|
127
|
+
!.pixi/config.toml
|
|
128
|
+
|
|
129
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
130
|
+
__pypackages__/
|
|
131
|
+
|
|
132
|
+
# Celery stuff
|
|
133
|
+
celerybeat-schedule*
|
|
134
|
+
celerybeat.pid
|
|
135
|
+
|
|
136
|
+
# Redis
|
|
137
|
+
*.rdb
|
|
138
|
+
*.aof
|
|
139
|
+
*.pid
|
|
140
|
+
|
|
141
|
+
# RabbitMQ
|
|
142
|
+
mnesia/
|
|
143
|
+
rabbitmq/
|
|
144
|
+
rabbitmq-data/
|
|
145
|
+
|
|
146
|
+
# ActiveMQ
|
|
147
|
+
activemq-data/
|
|
148
|
+
|
|
149
|
+
# SageMath parsed files
|
|
150
|
+
*.sage.py
|
|
151
|
+
|
|
152
|
+
# Environments
|
|
153
|
+
.env
|
|
154
|
+
.envrc
|
|
155
|
+
.venv
|
|
156
|
+
env/
|
|
157
|
+
venv/
|
|
158
|
+
ENV/
|
|
159
|
+
env.bak/
|
|
160
|
+
venv.bak/
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# pytype static type analyzer
|
|
181
|
+
.pytype/
|
|
182
|
+
|
|
183
|
+
# Cython debug symbols
|
|
184
|
+
cython_debug/
|
|
185
|
+
|
|
186
|
+
# PyCharm
|
|
187
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
188
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
189
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
190
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
191
|
+
# .idea/
|
|
192
|
+
|
|
193
|
+
# Abstra
|
|
194
|
+
# Abstra is an AI-powered process automation framework.
|
|
195
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
196
|
+
# Learn more at https://abstra.io/docs
|
|
197
|
+
.abstra/
|
|
198
|
+
|
|
199
|
+
# Visual Studio Code
|
|
200
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
201
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
202
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
203
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
204
|
+
# .vscode/
|
|
205
|
+
# Temporary file for partial code execution
|
|
206
|
+
tempCodeRunnerFile.py
|
|
207
|
+
|
|
208
|
+
# Ruff stuff:
|
|
209
|
+
.ruff_cache/
|
|
210
|
+
|
|
211
|
+
# PyPI configuration file
|
|
212
|
+
.pypirc
|
|
213
|
+
|
|
214
|
+
# Marimo
|
|
215
|
+
marimo/_static/
|
|
216
|
+
marimo/_lsp/
|
|
217
|
+
__marimo__/
|
|
218
|
+
|
|
219
|
+
# Streamlit
|
|
220
|
+
.streamlit/secrets.toml
|
|
221
|
+
|
|
222
|
+
# プロジェクト固有
|
|
223
|
+
PROJECT.md
|
|
224
|
+
開発資料/
|
|
225
|
+
|
|
226
|
+
# Patent Checker artifacts and local test fixtures (never tracked)
|
|
227
|
+
.patent-checker/
|
|
228
|
+
tests/fixtures/
|
|
229
|
+
|
|
230
|
+
# Container secrets mounted by compose.yaml (secrets/README.md stays tracked)
|
|
231
|
+
secrets/*.txt
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
|
|
3
|
+
# Patent Checker container image.
|
|
4
|
+
#
|
|
5
|
+
# The image is built in two stages because the build needs uv, a writable
|
|
6
|
+
# cache and the whole source tree, while running the server needs none of
|
|
7
|
+
# them: the runtime stage copies only `/app/.venv`, the virtual environment
|
|
8
|
+
# uv resolved from `uv.lock`, so uv itself, the build cache and the sources
|
|
9
|
+
# never reach a published layer. Both stages sit on the same
|
|
10
|
+
# `python:3.12-slim-trixie` base (Debian pinned so that the runtime does not
|
|
11
|
+
# drift under the venv), which is what makes that copy safe -- the venv
|
|
12
|
+
# holds symlinks into `/usr/local`, and the interpreter they point at has to
|
|
13
|
+
# be the identical build.
|
|
14
|
+
#
|
|
15
|
+
# Networking: the server binds 0.0.0.0 because a container's own loopback is
|
|
16
|
+
# unreachable from the host. Binding a non-loopback address makes the server
|
|
17
|
+
# demand PATENT_CHECKER_SERVER_ALLOWED_HOSTS, set here to the loopback names
|
|
18
|
+
# only. That is deliberate: the supported deployment publishes the port on
|
|
19
|
+
# the *host's* loopback (see `127.0.0.1:8642:8642` in compose.yaml), so the
|
|
20
|
+
# only Host headers that can legitimately arrive are `localhost` and
|
|
21
|
+
# `127.0.0.1`, and a DNS-rebinding attempt spelling any other name is
|
|
22
|
+
# refused. Serving a LAN means overriding that variable with the names
|
|
23
|
+
# clients really use and terminating TLS in front -- this transport is
|
|
24
|
+
# plain HTTP.
|
|
25
|
+
|
|
26
|
+
FROM python:3.12-slim-trixie AS builder
|
|
27
|
+
|
|
28
|
+
COPY --from=ghcr.io/astral-sh/uv:0.12 /uv /uvx /bin/
|
|
29
|
+
|
|
30
|
+
# Compile bytecode at install time so the first request does not pay for it;
|
|
31
|
+
# copy out of the cache mount instead of hardlinking, because the cache lives
|
|
32
|
+
# on a different filesystem than the layer; and never let uv download its own
|
|
33
|
+
# interpreter, so the venv is always built against the image's python.
|
|
34
|
+
ENV UV_COMPILE_BYTECODE=1 \
|
|
35
|
+
UV_LINK_MODE=copy \
|
|
36
|
+
UV_PYTHON_DOWNLOADS=never
|
|
37
|
+
|
|
38
|
+
WORKDIR /app
|
|
39
|
+
|
|
40
|
+
# Dependencies first, from the lockfile alone. This layer is reused for as
|
|
41
|
+
# long as uv.lock and pyproject.toml are untouched, which is why they are
|
|
42
|
+
# bind-mounted rather than copied: copying them would invalidate the layer on
|
|
43
|
+
# every unrelated file change.
|
|
44
|
+
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
45
|
+
--mount=type=bind,source=uv.lock,target=uv.lock \
|
|
46
|
+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
|
47
|
+
uv sync --locked --no-install-project --no-dev
|
|
48
|
+
|
|
49
|
+
COPY . /app
|
|
50
|
+
|
|
51
|
+
# Then the project itself, installed as a built wheel (`--no-editable`) so
|
|
52
|
+
# the runtime image does not need the source tree to stay in place. The wheel
|
|
53
|
+
# carries the bundled Skill, which is why README.md, LICENSE and skills/ must
|
|
54
|
+
# be part of the build context (see .dockerignore).
|
|
55
|
+
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
56
|
+
uv sync --locked --no-dev --no-editable
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
FROM python:3.12-slim-trixie
|
|
60
|
+
|
|
61
|
+
LABEL org.opencontainers.image.source="https://github.com/xhighhongo41/patent-checker" \
|
|
62
|
+
org.opencontainers.image.licenses="Apache-2.0" \
|
|
63
|
+
org.opencontainers.image.description="Patent prior-art exploration MCP server; it explores prior art and does not judge infringement"
|
|
64
|
+
|
|
65
|
+
# An unprivileged user owns /data, the only path the server ever writes to.
|
|
66
|
+
RUN useradd --uid 1000 --user-group --create-home app \
|
|
67
|
+
&& mkdir -p /data \
|
|
68
|
+
&& chown app:app /data
|
|
69
|
+
|
|
70
|
+
COPY --from=builder --chown=app:app /app/.venv /app/.venv
|
|
71
|
+
|
|
72
|
+
ENV PATH="/app/.venv/bin:$PATH" \
|
|
73
|
+
PATENT_CHECKER_DATA_DIR=/data \
|
|
74
|
+
PATENT_CHECKER_SERVER_HOST=0.0.0.0 \
|
|
75
|
+
PATENT_CHECKER_SERVER_ALLOWED_HOSTS=localhost,127.0.0.1 \
|
|
76
|
+
PATENT_CHECKER_LOG_LEVEL=info
|
|
77
|
+
|
|
78
|
+
USER app
|
|
79
|
+
WORKDIR /data
|
|
80
|
+
VOLUME ["/data"]
|
|
81
|
+
EXPOSE 8642
|
|
82
|
+
|
|
83
|
+
# curl is deliberately not installed: the venv's python can probe the
|
|
84
|
+
# unauthenticated health endpoint on its own, and every package left out of
|
|
85
|
+
# the runtime image is one less thing to patch.
|
|
86
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
87
|
+
CMD python -c "import sys, urllib.request; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8642/health', timeout=3).status == 200 else 1)"
|
|
88
|
+
|
|
89
|
+
ENTRYPOINT ["patent-checker"]
|
|
90
|
+
CMD ["serve"]
|