Skip to content
Closed
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
34 changes: 17 additions & 17 deletions .github/workflows/cflite_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ jobs:
fail-fast: false
matrix:
sanitizer:
- address
- undefined
- address
- undefined
steps:
- name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@52ecc61cb587ee99c26825a112a21abf19c7448c # main
with:
language: python
github-token: ${{ secrets.GITHUB_TOKEN }}
sanitizer: ${{ matrix.sanitizer }}
- name: Run Fuzzers (${{ matrix.sanitizer }})
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@52ecc61cb587ee99c26825a112a21abf19c7448c # main
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fuzz-seconds: 600
mode: 'code-change'
sanitizer: ${{ matrix.sanitizer }}
- name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@52ecc61cb587ee99c26825a112a21abf19c7448c # main
with:
language: python
github-token: ${{ secrets.GITHUB_TOKEN }}
sanitizer: ${{ matrix.sanitizer }}
- name: Run Fuzzers (${{ matrix.sanitizer }})
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@52ecc61cb587ee99c26825a112a21abf19c7448c # main
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fuzz-seconds: 600
mode: "code-change"
sanitizer: ${{ matrix.sanitizer }}
8 changes: 2 additions & 6 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ on:
branch_protection_rule:
schedule:
# Weekly on Saturdays.
- cron: '30 1 * * 6'
- cron: "30 1 * * 6"
push:
branches: [ main, master ]
branches: [main, master]

# Declare default permissions as read only.
permissions: read-all
Expand Down Expand Up @@ -57,10 +57,6 @@ jobs:

# required for Code scanning alerts
- name: "Upload SARIF results to code scanning"

uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5

uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v3.29.5

with:
sarif_file: results.sarif
18 changes: 7 additions & 11 deletions .github/workflows/smoke-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ name: Smoke Tests
on:
workflow_dispatch:
schedule:
- cron: '0 6 * * *'
- cron: "0 6 * * *"
push:
branches:
- master
paths:
- 'copi.owasp.org/**'
- 'tests/scripts/smoke_tests.py'
- '.github/workflows/smoke-tests.yaml'
- "copi.owasp.org/**"
- "tests/scripts/smoke_tests.py"
- ".github/workflows/smoke-tests.yaml"

permissions:
contents: read
Expand All @@ -27,8 +27,8 @@ jobs:
- name: Get Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.12'
cache: 'pipenv'
python-version: "3.12"
cache: "pipenv"

- name: Install dependencies
run: |
Expand All @@ -50,11 +50,7 @@ jobs:
docker build -t copi-test-image copi.owasp.org

echo "Generating SECRET_KEY_BASE"
SECRET_KEY_BASE=$(python - <<'PY'
import secrets
print(secrets.token_hex(64))
PY
)
SECRET_KEY_BASE=$(python -c 'import secrets; print(secrets.token_hex(64))')

echo "Starting Copi application container"
docker run -d --name copi-app --network copi-net -p 4000:4000 \
Expand Down
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pytest-cov = "==7.0.0"
freezegun = "==1.5.5"
security = "==1.3.1"
types-pyyaml = "==6.0.12.20250915"
pydantic = "==2.12.5"

[packages]
idna = "==3.11"
Expand Down
Binary file added scripts/before_logs.txt
Binary file not shown.
46 changes: 46 additions & 0 deletions scripts/card_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# scripts/card_models.py
from pydantic import BaseModel, Field, ValidationError, ConfigDict
from typing import Dict, List, Optional, Any


class Card(BaseModel):
"""Individual card model matching Cornucopia YAML structure."""
model_config = ConfigDict(extra='forbid')

id: str = Field(..., min_length=1, description="Card identifier (e.g., 'VE2', 'ATJ')")
value: str = Field(..., min_length=1, description="Card value (e.g., '2', '3', 'J', 'Q', 'K', 'A')")
url: str = Field(..., min_length=1, description="Card URL")
desc: str = Field(..., min_length=10, description="Card description")
misc: Optional[str] = Field(None, description="Optional miscellaneous information")
card: Optional[str] = Field(None, description="Optional card type (e.g., 'Joker')")


class Suit(BaseModel):
"""Suit model containing cards."""
model_config = ConfigDict(extra='forbid')

id: str = Field(..., min_length=1, description="Suit identifier (e.g., 'VE', 'AT')")
name: str = Field(..., min_length=1, description="Suit name")
cards: List[Card] = Field(default_factory=list, description="List of cards in this suit")


class Meta(BaseModel):
"""Metadata model for YAML files."""
model_config = ConfigDict(extra='forbid')

edition: str = Field(..., min_length=1, description="Edition (e.g., 'webapp', 'mobileapp')")
component: str = Field(..., min_length=1, description="Component (e.g., 'cards')")
language: str = Field(..., min_length=2, description="Language code (e.g., 'EN', 'es')")
version: str = Field(..., min_length=1, description="Version (e.g., '3.0', '1.1')")


class CornucopiaData(BaseModel):
"""Main model for Cornucopia YAML card data."""
model_config = ConfigDict(extra='allow') # Allow extra fields at top level

meta: Meta = Field(..., description="File metadata")
suits: List[Suit] = Field(default_factory=list, description="List of suits containing cards")


# Usage example (for testing):
# validated = CornucopiaData(**yaml_data)
13 changes: 13 additions & 0 deletions scripts/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from pathlib import Path
from pathvalidate.argparse import validate_filepath_arg
from pathvalidate import sanitize_filepath
from scripts.card_models import CornucopiaData, ValidationError


class ConvertVars:
Expand Down Expand Up @@ -737,6 +738,18 @@ def get_language_data(
with open(language_file, "r", encoding="utf-8") as f:
try:
data = yaml.safe_load(f)
# Validate with Pydantic for card files
if data and "meta" in data and data.get("meta", {}).get("component") == "cards":
try:
validated_data = CornucopiaData(**data)
logging.debug(f" --- YAML validation successful for {language_file}")
# Return the original data structure to maintain compatibility
# but now we know it's valid
data = validated_data.model_dump()
except ValidationError as e:
logging.error(f"Invalid card YAML structure in {language_file}: {e.errors()}")
# Return empty dict to prevent processing invalid data
return {}
except yaml.YAMLError as e:
logging.error(f"Error loading yaml file: {language_file}. Error = {e}")
data = {}
Expand Down
Loading
Loading