queryapigate 0.34.1__tar.gz → 0.34.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {queryapigate-0.34.1/queryapigate.egg-info → queryapigate-0.34.2}/PKG-INFO +1 -1
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/__init__.py +1 -1
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/definitions.py +1 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/engine.py +1 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/mongotools.py +19 -1
- {queryapigate-0.34.1 → queryapigate-0.34.2/queryapigate.egg-info}/PKG-INFO +1 -1
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_events_server.py +8 -6
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_jwt.py +6 -3
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_mongotools.py +11 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_queryapigate.py +29 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/LICENSE +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/README.md +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/pyproject.toml +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/__main__.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/accesslog.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/adminroles.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/admins.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/agentwrites.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/alerts.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/apikeys.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/app.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/auditchain.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/auditstream.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/aws.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/broadcast.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/bundle.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/cache.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/cli.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/collection_admin.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/config.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/configcode.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/AccessMapPage-BVQ6wRwp.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/AdministratorsPage-BiUGhISO.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/AgentsPage-CSA-qCUv.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/AlertsPage-MYZoziNZ.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/ApiKeysPage-BZISE5oJ.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/ApprovalsPage-CUiEkHq3.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/AuditLogPage-D9vrSHU7.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/CachingPage-2hjur6KQ.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/CodeBox-BZY9RBv5.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/ConnectionsPage-D26k-98S.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/DesignerPage-B_os91xI.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/DestinationsPage--bjoNE0y.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/ExportsPage-5ai6Ojbl.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/HelpPage-DNaGeh-8.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/HomePage-DINN_eBD.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/Managed-CVE0layM.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/MetricsPage-D6UAGhYP.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/RepositoryPage-BvsZyKvp.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/Results-D8fDmPdY.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/RolesPage-BdEQdLFD.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/SchemaBrowser-Bu0NvoUy.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/SettingsPage-BQhT4xlX.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/StatTile-DEmSFOkX.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/Time-MA05YtZP.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/forms-BSqwVHNJ.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/forms-C6RLe1F3.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/icons-DQ8_pv9M.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/index-BLd0t6vZ.css +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/index-sn5NUET1.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/maskRules-BGQ7mS0j.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/reach-2gDU11-l.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/shared-D5ownoD-.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/state-O13cl7cO.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/useMutation-BF7AWw3p.js +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/favicon.svg +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/index.html +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/cors.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/databases.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/db.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/deprecations.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/descriptions.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/destinations.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/duckfiles.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/errors.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/events.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/examples.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/experimental.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/exporting.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/exports.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/formats.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/governance.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/gunicorn_conf.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/history.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/instances.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/jwtauth.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/lib/h2-2.2.224.jar +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/limits.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/logging_setup.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/masking.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/mcp_server.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/metrics.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/oidc.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/openapi.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/params.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/parquet.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/pool.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/postman.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/quotas.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/ratelimit.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/rediscache.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/rekey.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/runners.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/schema.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/secheaders.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/secretrefs.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/__init__.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/access.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/administrators.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/audit.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/collections.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/connections.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/descriptions.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/destinations.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/exports.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/mcp.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/services/queries.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/sqlflow.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/sqltools.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/sso.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/store.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/tableguard.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/tracing.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/usage.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/v1.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/v1_spec.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/vault.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate.egg-info/SOURCES.txt +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate.egg-info/dependency_links.txt +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate.egg-info/entry_points.txt +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate.egg-info/requires.txt +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate.egg-info/top_level.txt +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/setup.cfg +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_adhoc_history.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_adminroles.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_admins.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_agent_writes.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_alerts.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_api_administrators.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_api_keys.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_api_v1.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_audit_chain.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_audit_log.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_audit_siem.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_audit_stream.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_aws.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_backup_restore.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_broadcast.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_cli.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_collection_bundle.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_collection_postman.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_collections.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_configcode.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_connection_encryption.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_console.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_cors_and_rate_limit.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_data_protection.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_databases.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_db.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_dependency_floors.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_deprecations.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_descriptions.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_destinations.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_docs_site.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_duckdb.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_duckdb_files.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_errors.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_events.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_examples.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_experimental.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_export_security.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_exporting.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_exports.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_fips.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_helm.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_history.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_howto.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_instances.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_integration.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_jdbc.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_key_rotation.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_limits.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_masking.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_masking_requests.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_mcp.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_mcp_keycloak.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_mcp_oauth.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_multinode.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_observability.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_oidc.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_params.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_parquet.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_pool.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_publishing.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_query_window.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_quotas.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_rekey.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_release_check.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_response_cache.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_roles.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_rolling_upgrade.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_secretrefs.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_security_headers.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_settings.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_shared_rate_limit.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_sql_guard_fuzz.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_sql_guard_writes.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_sqlflow.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_sso.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_sso_keycloak.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_supply_chain.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_tableguard.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_tracing.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_upgrades.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_usage.py +0 -0
- {queryapigate-0.34.1 → queryapigate-0.34.2}/tests/test_vault.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: queryapigate
|
|
3
|
-
Version: 0.34.
|
|
3
|
+
Version: 0.34.2
|
|
4
4
|
Summary: Turn SQL into governed REST APIs over MySQL, PostgreSQL, ClickHouse, SQLite, DuckDB, H2, MongoDB, and Parquet/CSV/JSON files - JSON, CSV, Parquet or Excel out, with scoped keys, an admin Console and MCP for AI agents.
|
|
5
5
|
Author-email: Anantha Raju C <arcswdev@gmail.com>
|
|
6
6
|
License-Expression: FSL-1.1-MIT
|
|
@@ -150,6 +150,7 @@ def validate_definition(data):
|
|
|
150
150
|
for extra in ('mongo_projection', 'mongo_sort'):
|
|
151
151
|
if data.get(extra) is not None:
|
|
152
152
|
fields[extra] = as_object(data.get(extra), extra)
|
|
153
|
+
mongotools.validate_options(fields.get('mongo_projection'), fields.get('mongo_sort'))
|
|
153
154
|
else:
|
|
154
155
|
fields['sql_query'] = data['sql_query']
|
|
155
156
|
return fields, collection
|
|
@@ -151,6 +151,7 @@ def execute_mongo(collection, filter_doc, connection_name, limit, offset, params
|
|
|
151
151
|
if details['db'] != 'mongo':
|
|
152
152
|
raise ApiError(f"'{connection_name}' is not a mongo connection", code='wrong_connection_type')
|
|
153
153
|
filter_doc = mongotools.validate_filter(filter_doc or {})
|
|
154
|
+
mongotools.validate_options(projection, sort)
|
|
154
155
|
timeout, limit = limits.timeout(timeout), limits.rows(limit)
|
|
155
156
|
if params:
|
|
156
157
|
filter_doc = mongotools.fill_placeholders(filter_doc, params)
|
|
@@ -55,10 +55,20 @@ def fill_placeholders(filter_doc, values):
|
|
|
55
55
|
|
|
56
56
|
Unlike sqltools.fill_placeholders, this never produces text to re-parse - the substituted value becomes
|
|
57
57
|
a real value in the returned document, so it can be a number, bool or null, not just safe text.
|
|
58
|
+
|
|
59
|
+
A value is a scalar, or a list of them - never a document. An object there is an operator the query's author
|
|
60
|
+
didn't write: `{"name": ":u"}` given `{"$ne": null}` matches every document, and `{"$function": ...}` runs
|
|
61
|
+
JavaScript on the server, past validate_filter(), which saw only the placeholder.
|
|
58
62
|
"""
|
|
59
|
-
|
|
63
|
+
used = set(placeholder_names(filter_doc))
|
|
64
|
+
missing = sorted(used - set(values))
|
|
60
65
|
if missing:
|
|
61
66
|
raise ApiError(f"No value provided for placeholder(s): {', '.join(missing)}", code='param_required')
|
|
67
|
+
for name in sorted(used):
|
|
68
|
+
value = values[name]
|
|
69
|
+
if isinstance(value, dict) or (isinstance(value, list) and any(isinstance(v, (dict, list)) for v in value)):
|
|
70
|
+
raise ApiError(f"'{name}' must be a value or a list of values, not a document - it would be read as "
|
|
71
|
+
'query operators', code='param_invalid')
|
|
62
72
|
return _substitute(filter_doc, values)
|
|
63
73
|
|
|
64
74
|
|
|
@@ -81,3 +91,11 @@ def validate_filter(filter_doc):
|
|
|
81
91
|
raise ApiError('filter must be a JSON object', code='invalid_filter')
|
|
82
92
|
_check_forbidden(filter_doc)
|
|
83
93
|
return filter_doc
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def validate_options(projection, sort):
|
|
97
|
+
"""The same check over a find()'s projection and sort: MongoDB 4.4+ evaluates aggregation expressions in a
|
|
98
|
+
projection, so `{"x": {"$function": ...}}` there runs JavaScript on the server as surely as in the filter."""
|
|
99
|
+
for document in (projection, sort):
|
|
100
|
+
if document is not None:
|
|
101
|
+
_check_forbidden(document)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: queryapigate
|
|
3
|
-
Version: 0.34.
|
|
3
|
+
Version: 0.34.2
|
|
4
4
|
Summary: Turn SQL into governed REST APIs over MySQL, PostgreSQL, ClickHouse, SQLite, DuckDB, H2, MongoDB, and Parquet/CSV/JSON files - JSON, CSV, Parquet or Excel out, with scoped keys, an admin Console and MCP for AI agents.
|
|
5
5
|
Author-email: Anantha Raju C <arcswdev@gmail.com>
|
|
6
6
|
License-Expression: FSL-1.1-MIT
|
|
@@ -119,7 +119,9 @@ class EventServerTestCase(unittest.TestCase):
|
|
|
119
119
|
asyncio.run_coroutine_threadsafe(server.stop(), loop).result(10)
|
|
120
120
|
# Wait for the loop's worker threads too (asyncio.to_thread - checking a key opens a store connection):
|
|
121
121
|
# one still connecting when the test's patched environment is restored reads os.environ while it is
|
|
122
|
-
# being changed, which libpq does in C - and that crashes the interpreter, not just the test.
|
|
122
|
+
# being changed, which libpq does in C - and that crashes the interpreter, not just the test. For the
|
|
123
|
+
# same reason a test never changes os.environ while the server runs: it patches the config function that
|
|
124
|
+
# reads the setting instead (CI on a PostgreSQL store, 2026-10-14: a segfault in the metrics test).
|
|
123
125
|
asyncio.run_coroutine_threadsafe(loop.shutdown_default_executor(), loop).result(10)
|
|
124
126
|
loop.call_soon_threadsafe(loop.stop)
|
|
125
127
|
thread.join(5)
|
|
@@ -312,7 +314,7 @@ class EventLogTests(EventServerTestCase):
|
|
|
312
314
|
|
|
313
315
|
def test_a_run_sampled_out_of_history_is_still_an_event(self):
|
|
314
316
|
stream = self.open('admin')
|
|
315
|
-
with mock.patch.
|
|
317
|
+
with mock.patch.object(config, 'history_sample_rate', return_value=0.000001): # see start_server()
|
|
316
318
|
self.run_query(self.alice)
|
|
317
319
|
(_, payload), = stream.events(1)
|
|
318
320
|
self.assertEqual(payload['query'], 'q')
|
|
@@ -332,7 +334,7 @@ class EventLogTests(EventServerTestCase):
|
|
|
332
334
|
with db.transaction() as conn:
|
|
333
335
|
for occurred_at in ('2026-01-01 00:00:00', '2026-01-02 11:00:00', '2026-01-02 13:00:00'):
|
|
334
336
|
conn.execute(events.INSERT, events.run_columns('q', 1, {'executed_at': occurred_at}))
|
|
335
|
-
with mock.patch.
|
|
337
|
+
with mock.patch.object(config, 'events_retention_hours', return_value=12):
|
|
336
338
|
self.assertEqual(events.sweep(now=datetime(2026, 1, 3, 0, 0)), 2)
|
|
337
339
|
self.assertEqual([row[0] for row in db.connection().execute('SELECT occurred_at FROM events')],
|
|
338
340
|
['2026-01-02 13:00:00'])
|
|
@@ -415,7 +417,7 @@ class MetricsTests(EventServerTestCase):
|
|
|
415
417
|
self.assertIn('queryapigate_events_lag_seconds_count 1\n', text)
|
|
416
418
|
|
|
417
419
|
def test_the_metrics_token_applies(self):
|
|
418
|
-
with mock.patch.
|
|
420
|
+
with mock.patch.object(config, 'metrics_token', return_value='sesame'):
|
|
419
421
|
self.assertEqual(self.metrics().status, 401)
|
|
420
422
|
self.assertEqual(self.metrics(Authorization='Bearer sesame').status, 200)
|
|
421
423
|
|
|
@@ -447,7 +449,7 @@ class LimitTests(EventServerTestCase):
|
|
|
447
449
|
self.assertEqual((refused.status, refused.headers['retry-after']), (503, '5'))
|
|
448
450
|
|
|
449
451
|
def test_the_server_wide_rate_limit_applies_to_connection_attempts(self):
|
|
450
|
-
with mock.patch.
|
|
452
|
+
with mock.patch.object(config, 'rate_limit', return_value=config.parse_rate_limit('2/minute')):
|
|
451
453
|
statuses = [self.open('admin').status for _ in range(3)]
|
|
452
454
|
self.assertEqual(statuses, [200, 200, 429])
|
|
453
455
|
|
|
@@ -470,7 +472,7 @@ class LimitTests(EventServerTestCase):
|
|
|
470
472
|
|
|
471
473
|
class CorsTests(EventServerTestCase):
|
|
472
474
|
def test_an_allowed_origin_gets_cors_headers_and_a_preflight(self):
|
|
473
|
-
with mock.patch.
|
|
475
|
+
with mock.patch.object(config, 'cors_origins', return_value=frozenset({'https://app.example.com'})):
|
|
474
476
|
preflight = Stream(self.server.port, method='OPTIONS', headers={
|
|
475
477
|
'Origin': 'https://app.example.com', 'Access-Control-Request-Method': 'GET'})
|
|
476
478
|
self.assertEqual(preflight.status, 204)
|
|
@@ -371,6 +371,11 @@ class EventsServerTests(JwtTestCase):
|
|
|
371
371
|
from queryapigate import events
|
|
372
372
|
from tests.test_events_server import Stream
|
|
373
373
|
self.events, self.Stream = events, Stream
|
|
374
|
+
# Before the server starts, and undone after it stops: its worker threads open store connections, and
|
|
375
|
+
# libpq reads os.environ from C - changing it meanwhile crashes the interpreter (see test_events_server).
|
|
376
|
+
patcher = mock.patch.dict(os.environ, {'QUERYAPIGATE_HISTORY_FLUSH_INTERVAL': '0'})
|
|
377
|
+
patcher.start()
|
|
378
|
+
self.addCleanup(patcher.stop)
|
|
374
379
|
loop = asyncio.new_event_loop()
|
|
375
380
|
thread = threading.Thread(target=loop.run_forever, daemon=True)
|
|
376
381
|
thread.start()
|
|
@@ -380,13 +385,11 @@ class EventsServerTests(JwtTestCase):
|
|
|
380
385
|
|
|
381
386
|
def stop():
|
|
382
387
|
asyncio.run_coroutine_threadsafe(server.stop(), loop).result(10)
|
|
388
|
+
asyncio.run_coroutine_threadsafe(loop.shutdown_default_executor(), loop).result(10)
|
|
383
389
|
loop.call_soon_threadsafe(loop.stop)
|
|
384
390
|
thread.join(5)
|
|
385
391
|
loop.close()
|
|
386
392
|
self.addCleanup(stop)
|
|
387
|
-
patcher = mock.patch.dict(os.environ, {'QUERYAPIGATE_HISTORY_FLUSH_INTERVAL': '0'})
|
|
388
|
-
patcher.start()
|
|
389
|
-
self.addCleanup(patcher.stop)
|
|
390
393
|
|
|
391
394
|
def open(self, value):
|
|
392
395
|
stream = self.Stream(self.server.port, headers=bearer(value))
|
|
@@ -35,6 +35,17 @@ class FillPlaceholdersTests(unittest.TestCase):
|
|
|
35
35
|
self.assertEqual(result['age']['$gte'], 21)
|
|
36
36
|
self.assertIsInstance(result['age']['$gte'], int)
|
|
37
37
|
|
|
38
|
+
def test_a_document_is_never_a_value(self):
|
|
39
|
+
# Until 0.34.2 an undeclared placeholder took whatever JSON was sent: {"$ne": null} matched every document,
|
|
40
|
+
# and {"$function": ...} ran server-side JavaScript past validate_filter(), which saw only ':u'.
|
|
41
|
+
for value in ({'$ne': None}, {'$function': {'body': 'function() {}', 'args': [], 'lang': 'js'}},
|
|
42
|
+
[{'$gt': ''}], [['nested']]):
|
|
43
|
+
with self.subTest(value=value), self.assertRaises(ApiError) as caught:
|
|
44
|
+
mongotools.fill_placeholders({'name': ':u'}, {'u': value})
|
|
45
|
+
self.assertEqual(caught.exception.code, 'param_invalid')
|
|
46
|
+
self.assertEqual(mongotools.fill_placeholders({'name': {'$in': ':u'}}, {'u': ['a', 2, None]}),
|
|
47
|
+
{'name': {'$in': ['a', 2, None]}}) # a list of values is still a value
|
|
48
|
+
|
|
38
49
|
def test_substitutes_inside_a_list(self):
|
|
39
50
|
result = mongotools.fill_placeholders({'status': {'$in': [':a', ':b']}}, {'a': 'x', 'b': 'y'})
|
|
40
51
|
self.assertEqual(result['status']['$in'], ['x', 'y'])
|
|
@@ -1780,6 +1780,35 @@ class MongoQueryTests(ApiTestCase):
|
|
|
1780
1780
|
'collection': 'users', 'filter': {'$where': 'true'}, 'connection_name': 'mg'})
|
|
1781
1781
|
self.assertEqual(res.status_code, 403)
|
|
1782
1782
|
|
|
1783
|
+
def test_server_side_javascript_is_refused_in_a_projection_and_a_sort_too(self):
|
|
1784
|
+
# Until 0.34.2 only the filter was checked: MongoDB 4.4+ evaluates aggregation expressions in a find()
|
|
1785
|
+
# projection, so {"x": {"$function": ...}} there ran JavaScript on the database server.
|
|
1786
|
+
js = {'$function': {'body': 'function() { return 1; }', 'args': [], 'lang': 'js'}}
|
|
1787
|
+
for field in ('projection', 'sort'):
|
|
1788
|
+
with self.subTest(field=field), mock.patch('pymongo.MongoClient') as connect:
|
|
1789
|
+
res = self.client.post('/execute_mongo', json={
|
|
1790
|
+
'collection': 'users', 'connection_name': 'mg', field: {'x': js}})
|
|
1791
|
+
self.assertEqual((res.status_code, res.get_json()['code']), (403, 'mongo_operator_forbidden'))
|
|
1792
|
+
self.assertFalse(connect.called)
|
|
1793
|
+
saved = save_query(self.client, {
|
|
1794
|
+
'filename': 'js', 'author': 'a', 'description': 'd', 'query_type': 'mongo', 'mongo_collection': 'users',
|
|
1795
|
+
'mongo_filter': {}, 'mongo_projection': {'x': {'$accumulator': {}}}, 'connection_name': 'mg'})
|
|
1796
|
+
self.assertEqual((saved.status_code, saved.get_json()['code']), (403, 'mongo_operator_forbidden'))
|
|
1797
|
+
|
|
1798
|
+
def test_a_caller_cant_turn_a_parameter_into_operators(self):
|
|
1799
|
+
# Until 0.34.2: a saved query's undeclared placeholder, given {"$ne": null}, matched every document.
|
|
1800
|
+
self.assertEqual(save_query(self.client, {
|
|
1801
|
+
'filename': 'by_name', 'author': 'a', 'description': 'd', 'query_type': 'mongo',
|
|
1802
|
+
'mongo_collection': 'users', 'mongo_filter': {'name': ':u'}, 'connection_name': 'mg'}).status_code, 201)
|
|
1803
|
+
with mock.patch('pymongo.MongoClient') as connect:
|
|
1804
|
+
saved = self.client.post('/q/by_name', json={'params': {'u': {'$ne': None}}})
|
|
1805
|
+
adhoc = self.client.post('/execute_mongo', json={
|
|
1806
|
+
'collection': 'users', 'connection_name': 'mg', 'filter': {'$expr': ':p'},
|
|
1807
|
+
'params': {'p': {'$function': {'body': 'function() { return true; }', 'args': [], 'lang': 'js'}}}})
|
|
1808
|
+
for res in (saved, adhoc):
|
|
1809
|
+
self.assertEqual((res.status_code, res.get_json()['code']), (400, 'param_invalid'))
|
|
1810
|
+
self.assertFalse(connect.called)
|
|
1811
|
+
|
|
1783
1812
|
def test_collection_is_required(self):
|
|
1784
1813
|
res = self.client.post('/execute_mongo', json={'filter': {}, 'connection_name': 'mg'})
|
|
1785
1814
|
self.assertEqual(res.status_code, 400)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/AgentsPage-CSA-qCUv.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/AlertsPage-MYZoziNZ.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/ApiKeysPage-BZISE5oJ.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/CachingPage-2hjur6KQ.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/CodeBox-BZY9RBv5.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/ExportsPage-5ai6Ojbl.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/HelpPage-DNaGeh-8.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/HomePage-DINN_eBD.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/Managed-CVE0layM.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/MetricsPage-D6UAGhYP.js
RENAMED
|
File without changes
|
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/Results-D8fDmPdY.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/RolesPage-BdEQdLFD.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/StatTile-DEmSFOkX.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/Time-MA05YtZP.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/forms-BSqwVHNJ.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/forms-C6RLe1F3.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/icons-DQ8_pv9M.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/index-BLd0t6vZ.css
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/index-sn5NUET1.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/maskRules-BGQ7mS0j.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/reach-2gDU11-l.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/shared-D5ownoD-.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/state-O13cl7cO.js
RENAMED
|
File without changes
|
{queryapigate-0.34.1 → queryapigate-0.34.2}/queryapigate/console_dist/assets/useMutation-BF7AWw3p.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|