diff --git a/.github/workflows/security-scan-full.yml b/.github/workflows/security-scan-full.yml new file mode 100644 index 0000000..ca072f8 --- /dev/null +++ b/.github/workflows/security-scan-full.yml @@ -0,0 +1,67 @@ +name: Seqra + ZAP Security Scan (Full Mode) + +on: + push + +permissions: + contents: read + security-events: write + +jobs: + security-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + + - name: Build application + run: ./gradlew build -x test + + - name: Start Spring Boot application + run: | + ./gradlew bootRun > app.log 2>&1 & + echo $! > app.pid + + # Wait for application to be ready + echo "Waiting for application to start..." + for i in {1..30}; do + if curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application is ready!" + break + fi + echo "Waiting... ($i/30)" + sleep 2 + done + + if ! curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application failed to start" + cat app.log + exit 1 + fi + + - name: Run Seqra + ZAP security scan + uses: seqra/opentaint/github/zap@misonijnik/zap-action + with: + mode: 'full' + template: 'template.yaml' + target: 'http://localhost:8081' + artifact-name: 'seqra-zap-scan-results' + upload-sarif: 'false' + zap-cmd-options: '-addonupdate -addoninstall ascanrulesBeta -addoninstall pscanrulesBeta' + + - name: Stop application + if: always() + run: | + if [ -f app.pid ]; then + kill $(cat app.pid) || true + rm app.pid + fi diff --git a/.github/workflows/security-scan-pr.yml b/.github/workflows/security-scan-pr.yml new file mode 100644 index 0000000..fc50ff1 --- /dev/null +++ b/.github/workflows/security-scan-pr.yml @@ -0,0 +1,68 @@ +name: Seqra + ZAP Security Scan + +on: + pull_request + +permissions: + contents: read + pull-requests: write + security-events: write + +jobs: + security-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + + - name: Build application + run: ./gradlew build -x test + + - name: Start Spring Boot application + run: | + ./gradlew bootRun > app.log 2>&1 & + echo $! > app.pid + + # Wait for application to be ready + echo "Waiting for application to start..." + for i in {1..30}; do + if curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application is ready!" + break + fi + echo "Waiting... ($i/30)" + sleep 2 + done + + if ! curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application failed to start" + cat app.log + exit 1 + fi + + - name: Run Seqra + ZAP security scan + uses: seqra/opentaint/github/zap@misonijnik/zap-action + with: + mode: 'differential' + template: 'template.yaml' + target: 'http://localhost:8081' + artifact-name: 'seqra-zap-scan-results' + upload-sarif: 'true' + zap-cmd-options: '-addonupdate -addoninstall ascanrulesBeta -addoninstall pscanrulesBeta' + + - name: Stop application + if: always() + run: | + if [ -f app.pid ]; then + kill $(cat app.pid) || true + rm app.pid + fi diff --git a/.github/workflows/seqra-scan.yml b/.github/workflows/seqra-scan.yml new file mode 100644 index 0000000..270ce6e --- /dev/null +++ b/.github/workflows/seqra-scan.yml @@ -0,0 +1,30 @@ +name: Seqra Scan + +on: + pull_request + +jobs: + seqra-scan: + runs-on: ubuntu-latest + name: Run Seqra Analysis + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up JDK + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '21' + + - name: Run Seqra scan + uses: seqra/seqra-action@v2 + with: + project-root: '.' + seqra-version: 'v2' + severity: 'warning,error' + timeout: '15m' + verbosity: 'debug' + artifact-name: 'seqra-sarif' + upload-sarif: 'false' diff --git a/.github/workflows/zap-scan.yml b/.github/workflows/zap-scan.yml new file mode 100644 index 0000000..3b8fc44 --- /dev/null +++ b/.github/workflows/zap-scan.yml @@ -0,0 +1,78 @@ +name: ZAP Full Scan + +on: + pull_request + +permissions: + contents: read + pull-requests: write + +jobs: + zap-scan: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + + - name: Build application + run: ./gradlew build -x test + + - name: Start Spring Boot application + run: | + ./gradlew bootRun > app.log 2>&1 & + echo $! > app.pid + + echo "Waiting for application to start..." + for i in {1..30}; do + if curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application is ready!" + break + fi + echo "Waiting... ($i/30)" + sleep 2 + done + + if ! curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application failed to start" + cat app.log + exit 1 + fi + + - name: Create output directory + run: | + mkdir -p zap-output + chmod 777 zap-output + + - name: Run ZAP Automation Framework scan + uses: zaproxy/action-af@v0.2.0 + continue-on-error: true + with: + plan: 'full-scan.yaml' + docker_name: 'ghcr.io/zaproxy/zaproxy:stable' + cmd_options: '-addonupdate -addoninstall ascanrulesBeta -addoninstall pscanrulesBeta' + + - name: Stop application + if: always() + run: | + if [ -f app.pid ]; then + kill $(cat app.pid) || true + rm app.pid + fi + + - name: Upload ZAP scan results + uses: actions/upload-artifact@v4 + if: always() + with: + name: zap-full-scan-results + path: zap-output/ + retention-days: 30 diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/.zap/rules.tsv b/.zap/rules.tsv new file mode 100644 index 0000000..17d471c --- /dev/null +++ b/.zap/rules.tsv @@ -0,0 +1,119 @@ +# ZAP API Scan Rules Configuration + +# CWE-22: Path Traversal +6 WARN (Path Traversal - Active/release) + +# CWE-78: OS Command Injection +10048 WARN (Remote Code Execution - Shell Shock - Active/beta) +40045 IGNORE (Spring4Shell - Active/beta) +40048 IGNORE (Remote Code Execution - CVE-2021-44228 - Active/beta) +90020 WARN (Remote OS Command Injection - Active/release) +90037 IGNORE (Server Side Template Injection - Active/beta) + +# CWE-79: Cross-Site Scripting (XSS) +40012 WARN (Cross Site Scripting (Reflected) - Active/release) +40026 IGNORE (Cross Site Scripting (DOM Based) - Active/release) +40031 IGNORE (Cross Site Scripting (Persistent) - Active/release) + +# CWE-89: SQL Injection +40018 WARN (SQL Injection - Active/release) +40019 WARN (SQL Injection - MySQL - Active/beta) +40020 WARN (SQL Injection - Hypersonic SQL - Active/beta) +40021 WARN (SQL Injection - Oracle - Active/beta) +40022 WARN (SQL Injection - PostgreSQL - Active/beta) +40027 IGNORE (SQL Injection - SQLite - Active/beta) + +# CWE-94: Code Injection +40028 WARN (ELMAH Information Leak - Active/beta) +40032 IGNORE (.htaccess Information Leak - Active/beta) +90019 WARN (Server Side Code Injection - Active/release) + +# CWE-113: CRLF Injection +40003 WARN (CRLF Injection - Active/release) + +# CWE-117: Log Injection +40043 IGNORE (Log4Shell - Active/beta) +40047 IGNORE (CORS Header - Active/beta) + +# CWE-352: CSRF +20012 WARN (Anti CSRF Tokens Scanner - Active/beta) + +# CWE-601: Open Redirect +20019 WARN (External Redirect - Active/release) + +# CWE-611: XXE +90023 WARN (XML External Entity Attack - Active/beta) + +# CWE-643: XPath Injection +90021 WARN (XPath Injection - Active/beta) + +# CWE-917: Expression Language Injection +90025 WARN (Expression Language Injection - Active/beta) + +# CWE-918: SSRF +40046 IGNORE (SSRF - Active/beta) + +# CWE-943: NoSQL Injection +40033 IGNORE (NoSQL Injection - MongoDB - Active/beta) +90039 IGNORE (NoSQL Injection - Active/beta) + +# CWE-1336: Prototype Pollution +90035 IGNORE (Prototype Pollution - Active/beta) +90036 IGNORE (Prototype Pollution (Client Side) - Active/beta) + +# Additional passive scan rules to ignore +90003 IGNORE (Sub Resource Integrity Attribute Missing - Passive/release) +90004 IGNORE (Insufficient Site Isolation Against Spectre Vulnerability - Passive/release) + +# Disable all other active scan rules not listed above +0 IGNORE (Directory Browsing - Active/release) +2 IGNORE (Private IP Disclosure - Passive/release) +3 IGNORE (Session ID in URL Rewrite - Passive/release) +7 IGNORE (Remote File Inclusion - Active/release) +10010 IGNORE (Cookie No HttpOnly Flag - Passive/release) +10011 IGNORE (Cookie Without Secure Flag - Passive/release) +10012 IGNORE (Password Autocomplete in Browser - Passive/release) +10015 IGNORE (Incomplete or No Cache-control and Pragma HTTP Header Set - Passive/release) +10016 IGNORE (Web Browser XSS Protection Not Enabled - Passive/release) +10017 IGNORE (Cross-Domain JavaScript Source File Inclusion - Passive/release) +10019 IGNORE (Content-Type Header Missing - Passive/release) +10020 IGNORE (X-Frame-Options Header Scanner - Passive/release) +10021 IGNORE (X-Content-Type-Options Header Missing - Passive/release) +10023 IGNORE (Information Disclosure - Debug Error Messages - Passive/beta) +10024 IGNORE (Information Disclosure - Sensitive Informations in URL - Passive/beta) +10025 IGNORE (Information Disclosure - Sensitive Information in HTTP Referrer Header - Passive/beta) +10026 IGNORE (HTTP Parameter Override - Passive/beta) +10027 IGNORE (Information Disclosure - Suspicious Comments - Passive/beta) +10032 IGNORE (Viewstate Scanner - Passive/beta) +10040 IGNORE (Secure Pages Include Mixed Content - Passive/release) +10045 IGNORE (Source Code Disclosure - /WEB-INF folder - Active/beta) +10095 IGNORE (Backup File Disclosure - Active/beta) +10105 IGNORE (Weak Authentication Method - Passive/beta) +10202 IGNORE (Absence of Anti-CSRF Tokens - Passive/beta) +20014 IGNORE (HTTP Parameter Pollution scanner - Active/beta) +20015 IGNORE (Heartbleed OpenSSL Vulnerability - Active/beta) +20016 IGNORE (Cross-Domain Misconfiguration - Active/beta) +20017 IGNORE (Source Code Disclosure - CVE-2012-1823 - Active/beta) +20018 IGNORE (Remote Code Execution - CVE-2012-1823 - Active/beta) +30001 IGNORE (Buffer Overflow - Active/release) +30002 IGNORE (Format String Error - Active/release) +30003 IGNORE (Integer Overflow Error - Active/beta) +40008 IGNORE (Parameter Tampering - Active/release) +40009 IGNORE (Server Side Include - Active/release) +40013 IGNORE (Session Fixation - Active/beta) +40014 IGNORE (Cross Site Scripting (Persistent) - Active/release) +40016 IGNORE (Cross Site Scripting (Persistent) - Prime - Active/release) +40017 IGNORE (Cross Site Scripting (Persistent) - Spider - Active/release) +40023 IGNORE (Possible Username Enumeration - Active/beta) +42 IGNORE (Source Code Disclosure - SVN - Active/beta) +50000 IGNORE (Script Active Scan Rules - Active/release) +50001 IGNORE (Script Passive Scan Rules - Passive/release) +90001 IGNORE (Insecure JSF ViewState - Passive/beta) +90011 IGNORE (Charset Mismatch - Passive/beta) +90022 IGNORE (Application Error Disclosure - Passive/release) +90024 IGNORE (Generic Padding Oracle - Active/beta) +90026 IGNORE (SOAP Action Spoofing - Active/alpha) +90028 IGNORE (Insecure HTTP Method - Active/beta) +90029 IGNORE (SOAP XML Injection - Active/alpha) +90030 IGNORE (WSDL File Passive Scanner - Passive/alpha) +90033 IGNORE (Loosely Scoped Cookie - Passive/beta) diff --git a/full-scan.yaml b/full-scan.yaml new file mode 100644 index 0000000..063eb12 --- /dev/null +++ b/full-scan.yaml @@ -0,0 +1,180 @@ +env: + contexts: + - name: openapi-import + urls: + - http://localhost:8081 + includePaths: [] + excludePaths: + - http://localhost:8081/api/redirect/external$ + parameters: + failOnError: false + failOnWarning: false + continueOnFailure: true + progressToStdout: true +jobs: + - type: openapi + parameters: + context: openapi-import + targetUrl: http://localhost:8081 + apiUrl: http://localhost:8081/v3/api-docs + - type: activeScan-config + parameters: + maxRuleDurationInMins: 0 + maxScanDurationInMins: 0 + maxAlertsPerRule: 0 + threadPerHost: 40 + handleAntiCSRFTokens: true + injectPluginIdInHeader: true + inputVectors: + urlQueryStringAndDataDrivenNodes: + enabled: true + addParam: false + odata: true + postData: + enabled: true + multiPartFormData: true + xml: true + json: + enabled: true + scanNullValues: false + googleWebToolkit: false + directWebRemoting: false + urlPath: true + httpHeaders: + enabled: true + allRequests: false + cookieData: + enabled: true + encodeCookieValues: false + scripts: true + - type: activeScan-policy + parameters: + name: full-scan-policy + policyDefinition: + defaultStrength: INSANE + defaultThreshold: OFF + rules: + - id: 6 + threshold: MEDIUM + strength: INSANE + - id: 10048 + threshold: MEDIUM + strength: INSANE + - id: 40045 + threshold: MEDIUM + strength: INSANE + - id: 40048 + threshold: MEDIUM + strength: INSANE + - id: 90020 + threshold: MEDIUM + strength: INSANE + - id: 90037 + threshold: MEDIUM + strength: INSANE + - id: 40012 + threshold: MEDIUM + strength: INSANE + - id: 40026 + threshold: MEDIUM + strength: INSANE + - id: 40031 + threshold: MEDIUM + strength: INSANE + - id: 40018 + threshold: MEDIUM + strength: INSANE + - id: 40019 + threshold: MEDIUM + strength: INSANE + - id: 40020 + threshold: MEDIUM + strength: INSANE + - id: 40021 + threshold: MEDIUM + strength: INSANE + - id: 40022 + threshold: MEDIUM + strength: INSANE + - id: 40027 + threshold: MEDIUM + strength: INSANE + - id: 40028 + threshold: MEDIUM + strength: INSANE + - id: 40032 + threshold: MEDIUM + strength: INSANE + - id: 90019 + threshold: MEDIUM + strength: INSANE + - id: 40003 + threshold: MEDIUM + strength: INSANE + - id: 40043 + threshold: MEDIUM + strength: INSANE + - id: 40047 + threshold: MEDIUM + strength: INSANE + - id: 20012 + threshold: MEDIUM + strength: INSANE + - id: 20019 + threshold: MEDIUM + strength: INSANE + - id: 90023 + threshold: MEDIUM + strength: INSANE + - id: 90021 + threshold: MEDIUM + strength: INSANE + - id: 90025 + threshold: MEDIUM + strength: INSANE + - id: 40046 + threshold: MEDIUM + strength: INSANE + - id: 40033 + threshold: MEDIUM + strength: INSANE + - id: 90039 + threshold: MEDIUM + strength: INSANE + - id: 90035 + threshold: MEDIUM + strength: INSANE + - id: 90036 + threshold: MEDIUM + strength: INSANE + - type: activeScan + parameters: + context: openapi-import + policy: full-scan-policy + - type: report + parameters: + template: traditional-json + reportDir: /zap/wrk/zap-output + reportFile: 'zap_scan_results' + reportTitle: ZAP Full Scan Report + reportDescription: Full ZAP scan results for all imported API endpoints + risks: + - high + - medium + confidences: + - high + - medium + - low + - type: report + parameters: + template: traditional-html + reportDir: /zap/wrk/zap-output + reportFile: '{{yyyy-MM-dd}}-ZAP-Full-Report-[[site]]' + reportTitle: ZAP Full Scan Results + risks: + - high + - medium + confidences: + - high + - medium + - low diff --git a/main.py b/main.py new file mode 100644 index 0000000..5bf76e4 --- /dev/null +++ b/main.py @@ -0,0 +1,6 @@ +def main(): + print("Hello from seqra-java-spring-demo!") + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..86df634 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "seqra-java-spring-demo" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "pyyaml>=6.0.3", + "zaproxy>=0.5.0", +] diff --git a/src/main/java/org/example/controller/RedirectController.java b/src/main/java/org/example/controller/RedirectController.java new file mode 100644 index 0000000..94e72d9 --- /dev/null +++ b/src/main/java/org/example/controller/RedirectController.java @@ -0,0 +1,107 @@ +package org.example.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Map; + +@RestController +@RequestMapping("/api/redirect") +@Tag(name = "Redirect", description = "URL redirection and response management") +public class RedirectController { + + @GetMapping("/external") + @Operation(summary = "Redirect to external URL", description = "Redirects to an external URL with custom headers") + public void redirectExternal( + @Parameter(description = "Target URL") @RequestParam String url, + @Parameter(description = "Custom header value") @RequestParam(required = false) String headerValue, + HttpServletResponse response) throws IOException { + + if (headerValue != null && !headerValue.isEmpty()) { + response.setHeader("X-Custom-Header", headerValue); + } + + response.setHeader("Location", url); + response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + } + + @GetMapping("/tracking") + @Operation(summary = "Track and redirect", description = "Tracks click and redirects with tracking info") + public void trackAndRedirect( + @Parameter(description = "Destination URL") @RequestParam String destination, + @Parameter(description = "Tracking ID") @RequestParam(required = false) String trackingId, + @Parameter(description = "Campaign name") @RequestParam(required = false) String campaign, + HttpServletResponse response) throws IOException { + + if (trackingId != null) { + response.setHeader("X-Tracking-ID", trackingId); + } + + if (campaign != null) { + response.setHeader("X-Campaign", campaign); + } + + response.sendRedirect(destination); + } + + @PostMapping("/custom-response") + @Operation(summary = "Custom response headers", description = "Returns response with custom headers") + public ResponseEntity> customResponse( + @Parameter(description = "Custom header name") @RequestParam String headerName, + @Parameter(description = "Custom header value") @RequestParam String headerValue, + @RequestBody(required = false) Map body) { + + HttpHeaders headers = new HttpHeaders(); + headers.add(headerName, headerValue); + + Map responseBody = body != null ? body : Map.of( + "status", "success", + "message", "Custom headers applied" + ); + + return new ResponseEntity<>(responseBody, headers, HttpStatus.OK); + } + + @GetMapping("/cache-control") + @Operation(summary = "Set cache control", description = "Returns response with custom cache control headers") + public void setCacheControl( + @Parameter(description = "Cache control directive") @RequestParam String directive, + @Parameter(description = "Additional headers") @RequestParam(required = false) String additionalHeaders, + HttpServletResponse response) throws IOException { + + response.setHeader("Cache-Control", directive); + + if (additionalHeaders != null && !additionalHeaders.isEmpty()) { + String[] headers = additionalHeaders.split(";"); + for (String header : headers) { + String[] parts = header.split(":", 2); + if (parts.length == 2) { + response.setHeader(parts[0].trim(), parts[1].trim()); + } + } + } + + response.setContentType("application/json"); + response.getWriter().write("{\"status\":\"success\",\"cacheControl\":\"" + directive + "\"}"); + } + + @GetMapping("/content-disposition") + @Operation(summary = "Set content disposition", description = "Returns response with content disposition header") + public void setContentDisposition( + @Parameter(description = "Filename") @RequestParam String filename, + @Parameter(description = "Disposition type") @RequestParam(required = false, defaultValue = "attachment") String disposition, + HttpServletResponse response) throws IOException { + + String dispositionHeader = disposition + "; filename=" + filename; + response.setHeader("Content-Disposition", dispositionHeader); + response.setContentType("application/octet-stream"); + response.getWriter().write("File content for: " + filename); + } +} diff --git a/src/main/java/org/example/controller/TemplateController.java b/src/main/java/org/example/controller/TemplateController.java new file mode 100644 index 0000000..cefffcf --- /dev/null +++ b/src/main/java/org/example/controller/TemplateController.java @@ -0,0 +1,131 @@ +package org.example.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api/templates") +@Tag(name = "Templates", description = "Template processing and evaluation") +public class TemplateController { + + private final ExpressionParser parser = new SpelExpressionParser(); + + @PostMapping("/evaluate") + @Operation(summary = "Evaluate template expression", description = "Evaluates a template expression with provided context") + public ResponseEntity> evaluateExpression( + @Parameter(description = "Expression to evaluate") @RequestParam String expression, + @RequestBody(required = false) Map context) { + + try { + StandardEvaluationContext evalContext = new StandardEvaluationContext(); + + if (context != null) { + context.forEach(evalContext::setVariable); + } + + Expression exp = parser.parseExpression(expression); + Object result = exp.getValue(evalContext); + + return ResponseEntity.ok(Map.of( + "expression", expression, + "result", result != null ? result : "null", + "type", result != null ? result.getClass().getSimpleName() : "null" + )); + } catch (Exception e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Evaluation failed", + "message", e.getMessage() + )); + } + } + + @GetMapping("/render") + @Operation(summary = "Render template", description = "Renders a template string with dynamic values") + public ResponseEntity> renderTemplate( + @Parameter(description = "Template string") @RequestParam String template, + @Parameter(description = "User name") @RequestParam(required = false, defaultValue = "Guest") String userName) { + + try { + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariable("userName", userName); + context.setVariable("timestamp", System.currentTimeMillis()); + + Expression exp = parser.parseExpression(template); + Object rendered = exp.getValue(context); + + return ResponseEntity.ok(Map.of( + "template", template, + "rendered", rendered != null ? rendered.toString() : "", + "userName", userName + )); + } catch (Exception e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Rendering failed", + "message", e.getMessage() + )); + } + } + + @PostMapping("/calculate") + @Operation(summary = "Calculate expression", description = "Calculates mathematical or logical expressions") + public ResponseEntity> calculate( + @Parameter(description = "Calculation expression") @RequestParam String expr) { + + try { + Expression expression = parser.parseExpression(expr); + Object result = expression.getValue(); + + return ResponseEntity.ok(Map.of( + "expression", expr, + "result", result != null ? result : 0, + "success", true + )); + } catch (Exception e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Calculation failed", + "message", e.getMessage(), + "success", false + )); + } + } + + @GetMapping("/preview") + @Operation(summary = "Preview template output", description = "Previews template with sample data") + public ResponseEntity> previewTemplate( + @Parameter(description = "Template expression") @RequestParam String template) { + + Map sampleData = new HashMap<>(); + sampleData.put("user", "John Doe"); + sampleData.put("count", 42); + sampleData.put("active", true); + + try { + StandardEvaluationContext context = new StandardEvaluationContext(); + sampleData.forEach(context::setVariable); + + Expression exp = parser.parseExpression(template); + Object preview = exp.getValue(context); + + return ResponseEntity.ok(Map.of( + "template", template, + "preview", preview != null ? preview.toString() : "", + "sampleData", sampleData + )); + } catch (Exception e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Preview failed", + "message", e.getMessage() + )); + } + } +} diff --git a/template.yaml b/template.yaml new file mode 100644 index 0000000..11191d5 --- /dev/null +++ b/template.yaml @@ -0,0 +1,279 @@ +env: + contexts: + - name: openapi-import + urls: + - http://localhost:8081 + includePaths: [ ] + excludePaths: + - http://localhost:8081/api/redirect/external$ + parameters: + failOnError: false + failOnWarning: false + continueOnFailure: true + progressToStdout: true +jobs: + - type: openapi + parameters: + context: openapi-import + targetUrl: http://localhost:8081 + apiUrl: http://localhost:8081/v3/api-docs + - type: activeScan-config + parameters: + maxRuleDurationInMins: 0 + maxScanDurationInMins: 0 + maxAlertsPerRule: 0 + threadPerHost: 40 + handleAntiCSRFTokens: true + injectPluginIdInHeader: true + inputVectors: + urlQueryStringAndDataDrivenNodes: + enabled: true + addParam: false + odata: true + postData: + enabled: true + multiPartFormData: true + xml: true + json: + enabled: true + scanNullValues: false + googleWebToolkit: false + directWebRemoting: false + urlPath: true + httpHeaders: + enabled: true + allRequests: false + cookieData: + enabled: true + encodeCookieValues: false + scripts: true + - type: activeScan-policy + parameters: + name: policy-CWE-22 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 6 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-78 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 10048 + threshold: MEDIUM + strength: INSANE + - id: 40045 + threshold: MEDIUM + strength: INSANE + - id: 40048 + threshold: MEDIUM + strength: INSANE + - id: 90020 + threshold: MEDIUM + strength: INSANE + - id: 90037 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-79 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40012 + threshold: MEDIUM + strength: INSANE + - id: 40026 + threshold: MEDIUM + strength: INSANE + - id: 40031 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-89 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40018 + threshold: MEDIUM + strength: INSANE + - id: 40019 + threshold: MEDIUM + strength: INSANE + - id: 40020 + threshold: MEDIUM + strength: INSANE + - id: 40021 + threshold: MEDIUM + strength: INSANE + - id: 40022 + threshold: MEDIUM + strength: INSANE + - id: 40027 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-94 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40028 + threshold: MEDIUM + strength: INSANE + - id: 40032 + threshold: MEDIUM + strength: INSANE + - id: 90019 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-113 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40003 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-117 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40043 + threshold: MEDIUM + strength: INSANE + - id: 40047 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-352 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 20012 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-601 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 20019 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-611 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 90023 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-643 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 90021 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-917 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 90025 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-918 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40046 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-943 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40033 + threshold: MEDIUM + strength: INSANE + - id: 90039 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-1336 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 90035 + threshold: MEDIUM + strength: INSANE + - id: 90036 + threshold: MEDIUM + strength: INSANE + - type: report + parameters: + template: traditional-json + reportDir: /zap/wrk/zap-output + reportFile: 'seqra_zap_scan_results' + reportTitle: Seqra + ZAP Scan Report + reportDescription: Automated security scan results for filtering sarif + risks: + - high + - medium + confidences: + - high + - medium + - low + - type: report + parameters: + template: traditional-html + reportDir: /zap/wrk/zap-output + reportFile: '{{yyyy-MM-dd}}-ZAP-Report-[[site]]' + reportTitle: Seqra + ZAP scan results + risks: + - high + - medium + confidences: + - high + - medium + - low + - type: exitStatus + parameters: + okExitValue: 0 + errorExitValue: 0 + warnExitValue: 0 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..2fef78f --- /dev/null +++ b/uv.lock @@ -0,0 +1,185 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "seqra-java-spring-demo" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "pyyaml" }, + { name = "zaproxy" }, +] + +[package.metadata] +requires-dist = [ + { name = "pyyaml", specifier = ">=6.0.3" }, + { name = "zaproxy", specifier = ">=0.5.0" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "zaproxy" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/e9/43828866052d4154fbb11fee6cb842d3e74f46d116be626bfa53624572c0/zaproxy-0.5.0.tar.gz", hash = "sha256:3a952d7ec9af7a689a986400dcd885abf4685152119b1390ee8a42a2877636c8", size = 38597, upload-time = "2025-12-15T15:39:17.732Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/d0/f57fee17a8d3015ca868b120966793e76d258503056530c7b08a6d52972b/zaproxy-0.5.0-py3-none-any.whl", hash = "sha256:532125007c2381ae2d121774a7da9f69e045e040e3a448772988cc17eba472a9", size = 73295, upload-time = "2025-12-15T15:39:16.278Z" }, +]