From 98d1dc376d77e65059c372df02dd8da0f3825437 Mon Sep 17 00:00:00 2001 From: pstlouis Date: Fri, 3 Jan 2025 17:38:50 -0500 Subject: [PATCH] initial commit Signed-off-by: pstlouis --- .github/dependabot.yml | 26 +++ .github/workflows/checks.yml | 41 ++++ .github/workflows/publish-release.yml | 30 +++ .gitignore | 3 + README.md | 31 ++- oca/__init__.py | 0 oca/main.py | 41 ++++ oca/processor.py | 169 +++++++++++++++ poetry.lock | 297 ++++++++++++++++++++++++++ pyproject.toml | 21 ++ tests/__init__.py | 0 tests/test_said.py | 0 12 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/checks.yml create mode 100644 .github/workflows/publish-release.yml create mode 100644 oca/__init__.py create mode 100644 oca/main.py create mode 100644 oca/processor.py create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 tests/__init__.py create mode 100644 tests/test_said.py diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..c4f2ec0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,26 @@ +# For details on how this file works refer to: +# - https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +version: 2 +updates: + # Maintain dependencies for GitHub Actions + # - Check for updates once a week + # - Group all updates into a single PR + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + all-actions: + patterns: ["*"] + + # Maintain pip dependencies + - package-ecosystem: pip + directory: / + schedule: + interval: weekly + groups: + dev: + dependency-type: development + minor: + dependency-type: production + update-types: [minor, patch] \ No newline at end of file diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 0000000..dacc6fe --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,41 @@ +name: Checks + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + format: + name: Format and Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: psf/black@24.8.0 + with: + src: "./vcdm" + - uses: chartboost/ruff-action@v1 + with: + version: 0.3.4 + + test: + name: Tests + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.12"] + + steps: + - uses: actions/checkout@v4 + - name: Install poetry + run: pipx install poetry + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: poetry + - name: Install dependencies + run: poetry install + - name: Run pytest + run: poetry run pytest \ No newline at end of file diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 0000000..6a09c79 --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,30 @@ +name: Upload Python Package to PyPI when a Release is Created + +on: + release: + types: [created] + +jobs: + pypi-publish: + name: Publish release to PyPI + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/oca-cli + permissions: + id-token: write + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install poetry + - name: Build package + run: | + poetry build -f sdist + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 15201ac..f0af60e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Sample files +sample* + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/README.md b/README.md index d360a93..9802eff 100644 --- a/README.md +++ b/README.md @@ -1 +1,30 @@ -# oca-cli \ No newline at end of file +# oca-cli + +## Quickstart + +```bash +# install the package +pip install oca-cli + +# Create a sample schema file +SAMPLE_BUNDLE=$(cat < sample_schema.json + +# Draft an OCA Bundle +oca draft -f sample_schema.json > sample_draft.json + +# Edit the bundle then secure it +oca secure -f sample_draft.json > sample_bundle.json + +``` \ No newline at end of file diff --git a/oca/__init__.py b/oca/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oca/main.py b/oca/main.py new file mode 100644 index 0000000..e00314d --- /dev/null +++ b/oca/main.py @@ -0,0 +1,41 @@ +import typer +import json +from typing_extensions import Annotated +from oca.processor import OCAProcessor + +cli = typer.Typer() + +@cli.command() +def draft( + file: Annotated[str, typer.Option( + '-f', '--file', + help="Schema file name.", + prompt=True + )] = 'samples/schema.json' + ): + """Draft an OCA Bundle. + """ + with open(file, 'r') as f: + schema = json.loads(f.read()) + + drafted_bundle = OCAProcessor().draft_bundle(schema) + print(json.dumps(drafted_bundle, indent=2)) + +@cli.command() +def secure( + file: Annotated[str, typer.Option( + '-f', '--file', + help="OCA Bundle file name.", + prompt=True + )] = 'samples/bundle.json' + ): + """Secure an OCA Bundle. + """ + with open(file, 'r') as f: + bundle = json.loads(f.read()) + + secured_bundle = OCAProcessor().secure_bundle(bundle) + print(json.dumps(secured_bundle, indent=2)) + +if __name__ == "__main__": + typer.run(cli) \ No newline at end of file diff --git a/oca/processor.py b/oca/processor.py new file mode 100644 index 0000000..f551d3c --- /dev/null +++ b/oca/processor.py @@ -0,0 +1,169 @@ +import base64 +from blake3 import blake3 +import jcs +import json +import re + + +class OCAProcessorError(Exception): + """Generic OCAProcessor Error.""" + + +class OCAProcessor: + def __init__(self): + self.dummy_string = "#" * 44 + + def generate_said(self, value): + # https://datatracker.ietf.org/doc/html/draft-ssmith-said#name-generation-and-verification + # https://trustoverip.github.io/tswg-cesr-specification/#text-coding-scheme-design + return "E" + ( + base64.urlsafe_b64encode( + bytes([0]) + blake3(jcs.canonicalize(value)).digest() + ).decode() + ).lstrip("A") + + def secure_bundle(self, bundle): + capture_base = bundle[0] + overlays = capture_base.pop('overlays') + + capture_base["digest"] = self.dummy_string + capture_base["digest"] = self.generate_said(capture_base) + + for idx, overlay in enumerate(overlays): + overlays[idx]["capture_base"] = capture_base["digest"] + overlays[idx]["digest"] = self.dummy_string + overlays[idx]["digest"] = self.generate_said(overlays[idx]) + + secures_bundle = [capture_base | {"overlays": overlays}] + return secures_bundle + + def draft_bundle(self, schema): + capture_base = { + "type": "spec/capture_base/1.0", + "attributes": {attribute: 'Text' for attribute in schema['attributes']}, + "flagged_attributes": [], + 'overlays': [] + } + encoding = { + "type": "spec/overlays/character_encoding/1.0", + "default_character_encoding": "utf-8", + "attribute_character_encoding": {attribute: "utf-8" for attribute in schema['attributes']}, + } + capture_base['overlays'].append(encoding) + + labels = { + "type": "spec/overlays/label/1.0", + "lang": "en", + "attribute_labels": {attribute: attribute.replace('_', ' ').capitalize() for attribute in schema['attributes']}, + } + capture_base['overlays'].append(labels) + + information = { + "type": "spec/overlays/information/1.0", + "lang": "en", + "attribute_information": {attribute: 'Lorem ipsum' for attribute in schema['attributes']}, + } + capture_base['overlays'].append(information) + + meta = { + "type": "spec/overlays/meta/1.0", + "language": "en", + "issuer": schema["name"], + "name": schema["name"], + "description": schema['description'], + "credential_help_text": "Learn more", + "credential_support_url": "" + } + capture_base['overlays'].append(meta) + + branding = { + "type": "aries/overlays/branding/1.0", + "logo": "", + "background_image": "", + "background_image_slice": "", + "primary_background_color": "", + "secondary_background_color": "", + "primary_attribute": "", + "secondary_attribute": "", + "expiry_date_attribute": "", + } + capture_base['overlays'].append(branding) + return [capture_base] + + def create_bundle(self, credential_registration, credential_template): + capture_base = { + "type": "spec/capture_base/1.0", + "attributes": {}, + "flagged_attributes": [], + "digest": self.dummy_string, + } + labels = { + "type": "spec/overlays/label/1.0", + "lang": "en", + "attribute_labels": {}, + } + information = { + "type": "spec/overlays/information/1.0", + "lang": "en", + "attribute_information": {}, + } + meta = { + "type": "spec/overlays/meta/1.0", + "language": "en", + "issuer": credential_template["issuer"]["name"], + "name": credential_template["name"], + # "description": credential_template['description'], + } + + branding = { + "type": "aries/overlays/branding/1.0", + "primary_attribute": "entityId", + "secondary_attribute": "cardinalityId", + "primary_background_color": "#003366", + "secondary_background_color": "#00264D", + "logo": "https://avatars.githubusercontent.com/u/916280", + } + paths = {"type": "vc/overlays/path/1.0", "attribute_paths": {}} + clusters = { + "type": "vc/overlays/cluster/1.0", + "lang": "en", + "attribute_clusters": {}, + } + attributes = ( + credential_registration["corePaths"] + | credential_registration["subjectPaths"] + ) + for attribute in attributes: + capture_base["attributes"][attribute] = "Text" + labels["attribute_labels"][attribute] = " ".join( + re.findall("[A-Z][^A-Z]*", attribute) + ).upper() + paths["attribute_paths"][attribute] = attributes[attribute] + + overlays = [ + labels, + # information, + meta, + branding, + paths, + # clusters, + ] + + capture_base["digest"] = self.generate_said(capture_base) + for idx, overlay in enumerate(overlays): + overlays[idx]["capture_base"] = capture_base["digest"] + overlays[idx]["digest"] = self.dummy_string + overlays[idx]["digest"] = self.generate_said(overlays[idx]) + + bundle = capture_base | {"overlays": overlays} + return bundle + + def get_overlay(self, bundle, overlay_type): + return next( + ( + overlay + for overlay in bundle["overlays"] + if overlay["type"] == overlay_type + ), + None, + ) \ No newline at end of file diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..fafbeea --- /dev/null +++ b/poetry.lock @@ -0,0 +1,297 @@ +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. + +[[package]] +name = "blake3" +version = "1.0.1" +description = "Python bindings for the Rust blake3 crate" +optional = false +python-versions = "*" +files = [ + {file = "blake3-1.0.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4b24dc5bfaaeda911e5b7dbc99f47c9c5fc84d8841656bcb043ce5c402db3088"}, + {file = "blake3-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41018d98e062931a19dc3bfa77a0f34d5dfa756d5859f4cfe678ccbe24815b36"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6727d1ea501b6ef9f159a17039df449997ce95ee79c1a2be7898b54fd09659db"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b95a859c249b32191732c7fb55d006497c0d7bcb6211ce8e187b4e7cc64d7f1e"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3e99ffccb733468cd6a68da3b148a010721eeb6517d2892c2fad01ac088d8c4"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49033a5184cfe34fbed453f85de03564dfd6ae3271e2e33de56a11d2b453c163"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:251bf7693b434d067632d0dce41466774531f369d8aadc83c23d702bcf70fb29"}, + {file = "blake3-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8abd05d45b68bedb7341fdaaaf564c105b868cb4b89d7b29e74feb388430169e"}, + {file = "blake3-1.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7d61b5d4d7adacf9d6d22422d8bc0cee23264f8f886b39d634a522ed82c71a5"}, + {file = "blake3-1.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dcc46d88e820ab8ac200cb0547e287458c845fd412369fd8dc89a6ed466019d6"}, + {file = "blake3-1.0.1-cp310-cp310-win32.whl", hash = "sha256:bf3ae73c25e7dbaae099ce8511b525e50d981d437dd50f7a46a98a5ae417302a"}, + {file = "blake3-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1f887aca4798ae7f1899fa3ef8c399ba889c33aa9e7ebf067e7f1ade09144481"}, + {file = "blake3-1.0.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5f9ec05d9bd156e759fe9989c0d6e75b36410850a99296aa03eef7cd1198ca5e"}, + {file = "blake3-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46515c0b1dba02d48184417b8bae611d5c12b114f9a8b103746fb8d07b981042"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfbe2d39ef8a88a4e1937773d38f8a9b05f6328716e760342b3af0a7f3467869"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:855d9dc151017b8295fe10628b6bd8c1d10fc96f5c561fb4281faf70492a2104"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96fc1cbebc964678674c2bd27650e417a37a242ba73337ae2ef7f323e8b41b21"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a27cb7af5e337d08a5d1c3c440384911b65812509b30408c6212df9c13e3bb4"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9eee484df045753178eab4ede2c7570306ffdbf874cc5740ad08e549bd73714"}, + {file = "blake3-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ffda996220524e1e21d1d3a13a3638d49d67c1178d3313b03ecc03c49f8432f"}, + {file = "blake3-1.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f492c253bd6f8f0ffed0d185bbbfc4ccfcaff35e6846665e40154ac949a079bb"}, + {file = "blake3-1.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d38b6b9ef126e25ffecb7a64307df718f6831630c95d54301932660bb39af35a"}, + {file = "blake3-1.0.1-cp311-cp311-win32.whl", hash = "sha256:a9702eed8480c30f9da660ac7ecfc43f8ab2e9f0e1f3a4097ac4045628208696"}, + {file = "blake3-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:c1adb415561df49ffc19ebd4ab36025b3c263f4813ccdbddc467e9a4ac50d307"}, + {file = "blake3-1.0.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0b8781fd128e8a6448beb1ecc5863617f167af3f911a8013afc0f54319a5542b"}, + {file = "blake3-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5970ec6191e4b20ff5f4e3dce9fd368599677ade0765f1b6d5fc5df859ec18e3"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9405186a6fd2d6c9d87bcf6ebc30836f56e3a37e32697e0457d7f7c6b954e166"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:55917351d9b2f404ec1216be8394ec85db030294a8b0953c45c21c7b69ff10d8"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d174c9b21be3463a8aa9cc05d796cd70da7ec03c1e01d2aaa860e03e0eb3156"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8cae27f0df12b0d4387af16a9cbe1bb7d95c66d21c863706af94b05cefd0360"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef8ec9fa6d4d3446746621245090b4328dfff18f3a93c89a5ccf82a99b50accb"}, + {file = "blake3-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99a258e5fbaf85e96bf40a7463df5acef626d69a4e79c599366cde33ea56ea6e"}, + {file = "blake3-1.0.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b63a8e8579ba3a5513937a114bcc2acc07a746a6b903a46070bc5d3f7d32667d"}, + {file = "blake3-1.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a49580f0ee717b55843f15c9a1ffc5f946a9cb3d15bdda4024361fdfab6ef1e6"}, + {file = "blake3-1.0.1-cp312-cp312-win32.whl", hash = "sha256:ac6f55570db7da41b29de7af120a9edfa27c2e4724e7e4ebb0aa4b41414c9e41"}, + {file = "blake3-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddcc95cd5a4db73bd97a4d21eacfc793c057baae7d5b962f182467f861d2b4a6"}, + {file = "blake3-1.0.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:8c800eff0f5dbb13062cbe0970e3b922de473f10bd9729e166d58618b79082ad"}, + {file = "blake3-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:026b0e9c643fdc9f2fab8435b582fe59b705acdf2560197dd68c75f24c5db3a5"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d871674e43fe9cfb2a0e17267d988572f681b471c5bc7f262e35d6a56517380c"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:598905ac64221ea8823466e5fced2923eea8d6f508d61b177d3d3b00a65fdbed"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:756b4dcf4be33f1a8a518bc09b939eb7052ff00c2c118a66300ac7ae49898361"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:58e3736578577da9f0297482387f7babf5d08ab68d935d71345ad3740a219c11"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0a20efd5efd46074a7c073768e958c451985cba1c296eb79f6dd19c9d7d2173"}, + {file = "blake3-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:795bca3208fa11d2eeb26c2cb38e9a94f06cbec9f97fe6752b82b12645e5ff22"}, + {file = "blake3-1.0.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:46486763ffe98f0296055f5e6a413bbd5822fd298c461127b28f5b87bb3cdfa5"}, + {file = "blake3-1.0.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:06ef09f7a9e3b2971e123a0bb408edaaf4c33ae5917f0c11fe05520b5d85f847"}, + {file = "blake3-1.0.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:a13bb0ec647f280491d6ad9b105e5f529166d600a3f71f09412171870844792d"}, + {file = "blake3-1.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6c981943bdc8bf5eff1833fbaeafb4360b889af31deccf8f52813608d98fff78"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e7656948aba53b0e68380dc3cca6b2f93965973469ef99077f5855a0e62b9dc"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:795fe3c98ab81691c560faeac1181066931d7c14dbb8bf37bfbf4b46b9eb4e16"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62f04db159714e651c7e75e457b502bb121b343b756dd251608c859963a03a22"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74789ce1273c9d80929d33474dbcc8d2f06dd2a43e98cf47b8282cdfb2567367"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:352086155099ea7175b71e8d3d7589f1087470542ca1c763ef325775de5533ea"}, + {file = "blake3-1.0.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3bf4e616b5ade1557978d91897294f436d952b91ed5ef2cb9cd5765a03d3d42"}, + {file = "blake3-1.0.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:a911412d45c48364917875aad0fbaa9fcfa4b3b4fc9be8a21ccdcc83f0b15d93"}, + {file = "blake3-1.0.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9cb284412420f51f28378c65d5d218e8fe135e40940c185fd9dd3e5257f673d3"}, + {file = "blake3-1.0.1-cp313-cp313t-win32.whl", hash = "sha256:9b41e301a3bb962fa7d16b9b81b2f11f52af7dadd310aad9fb9e9317daaaf79a"}, + {file = "blake3-1.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:beb755df125c978d60bfbc8b35fbbf242aeb163ea7195f70541318b1f739f4fa"}, + {file = "blake3-1.0.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:7f395e608d1daf872b1a65e76b7e0a6fb825ddc1b25a954d777997f8bedaf285"}, + {file = "blake3-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3e717aceb2018f824a00fd0e1390698412ed34a51ecc234d99ef56111f4c1b3f"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feb1186b5e5c4ae86b1f84e450dbe6a8d0eacad8019d17067da3c84885c6388e"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7287dd5b2218cd3417a4c6922b52540f8f80d6685cab15ef910b22ae11c84ce6"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95c43b3886264cb982d8bad7a4b19b902fdb64d614073448638932abe1f16e41"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2037e5f8b319003b61dfc28b2d6f59b6ad757448dd986e422642e60f5dedb970"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a663565cfd2abf4307e67e69a1b0f17e6b118471eac325365425aee1074e8f3"}, + {file = "blake3-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56f73ea343a782fbc195424c6df265e38a183051ee72dd032560206b92a09b22"}, + {file = "blake3-1.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a6550ff4a3c4c6e85ec9bbe2082bd55cd47cc26e191419a0f8bc15dccc15b5f0"}, + {file = "blake3-1.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:87af8feb07126e3868d98a32da6a8639744aecb4e0dd8819a039aaa8687f078e"}, + {file = "blake3-1.0.1-cp38-cp38-win32.whl", hash = "sha256:77c68aaae459c67bb271271e114e08c5a240af509ee5925b30be3bc1ccd24ec9"}, + {file = "blake3-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:9a4f747db6d28f56939e1793fba3af3ddfe17d13819ddca60b758357a295ac84"}, + {file = "blake3-1.0.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e8a470f6f6111adbb89e054ba8f8d250369738ea07c0f4d7fca13c20c56e429d"}, + {file = "blake3-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6bf55e69e8bb4d26c72aff0da7e1703f48d6a3090eb1df4d646f77f419db2c3b"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0d8f7eff3dd243f9c7e8c3351aa7cfc0934c7ccf404c5d868bc3778b4982071"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:088ee326dc1a650f9a128f3876ce2507467263fe6dcbbd21a67ce119a85ba93b"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a6b8f8b2fd288b1bf99aa80a1c9690b527bca853f560cf91d853447aec37cb4"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de0e747e9c9dcd6242bf771a6dc54fcd294c8c613eed0fb2bd3aa5cbfa57db11"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2bdaca3949d6b40a9dd1e910a6a70d1f178ddc09b85fb8b82e08a1948479f8"}, + {file = "blake3-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae2282712c50d496037b0a694d5e1e31a7124d918a49c5feedef93146838ab0"}, + {file = "blake3-1.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d524f2e94b3251e262c4ace3c6ef0fd7637e3e9b54dd933f4d49aa38cf5f2c03"}, + {file = "blake3-1.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a625c9ecb89148c0c073ff0b3be14d17c5122879873783f8e85e8b1f18cc730a"}, + {file = "blake3-1.0.1-cp39-cp39-win32.whl", hash = "sha256:35214a680c990edc110de5093ede02a55e4379e8b1882b01e69e5b2a45f9091e"}, + {file = "blake3-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:d1817014c7c7ab64b5bfa8db2e0a8b9cd44e43e50ea86d50af568525c5607be9"}, + {file = "blake3-1.0.1.tar.gz", hash = "sha256:a76c54e91ca3a28be760575726f8dc01572734023fe88bf8dfa76913fa48a943"}, +] + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "jcs" +version = "0.2.1" +description = "JCS - JSON Canonicalization" +optional = false +python-versions = ">=3.6.2" +files = [ + {file = "jcs-0.2.1-py3-none-any.whl", hash = "sha256:e23a3e1de60f832d33cd811bb9c3b3be79219cdf95f63b88f0972732c3fa8476"}, + {file = "jcs-0.2.1.tar.gz", hash = "sha256:9f20360b2f3b0a410d65493b448f96306d80e37fb46283f3f4aa5db2c7c1472b"}, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "packaging" +version = "24.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pytest" +version = "8.3.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "rich" +version = "13.9.4" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "typer" +version = "0.15.1" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.7" +files = [ + {file = "typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847"}, + {file = "typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a"}, +] + +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.12" +content-hash = "4d4c3ed21122824a949c55f807e699e3cab4fbd941c503e67f6a95902465264e" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b377e9c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,21 @@ +[tool.poetry] +name = "oca" +version = "0.1.0" +description = "OCA Bundle management simplified." +authors = ["pstlouis "] +readme = "README.md" + +[tool.poetry.scripts] +oca = "oca.main:cli" + +[tool.poetry.dependencies] +python = "^3.12" +typer = "^0.15.1" +pytest = "^8.3.4" +blake3 = "^1.0.1" +jcs = "^0.2.1" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_said.py b/tests/test_said.py new file mode 100644 index 0000000..e69de29