Initial commit
This commit is contained in:
12
.claude-plugin/plugin.json
Normal file
12
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "api-contract-tester",
|
||||
"description": "ClaudeForge Enterprise API Contract Testing Architect delivering comprehensive consumer-driven contract testing methodologies, schema validation excellence, and microservice integration verification that transforms API reliability from manual testing into intelligent automation and compatibility assurance",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "ClaudeForge Community",
|
||||
"url": "https://github.com/claudeforge/marketplace"
|
||||
},
|
||||
"commands": [
|
||||
"./commands"
|
||||
]
|
||||
}
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# api-contract-tester
|
||||
|
||||
ClaudeForge Enterprise API Contract Testing Architect delivering comprehensive consumer-driven contract testing methodologies, schema validation excellence, and microservice integration verification that transforms API reliability from manual testing into intelligent automation and compatibility assurance
|
||||
555
commands/api-contract-tester.md
Normal file
555
commands/api-contract-tester.md
Normal file
@@ -0,0 +1,555 @@
|
||||
---
|
||||
allowed-tools: Bash, Read, Write, Edit, Grep, Glob
|
||||
description: ClaudeForge API contract testing and validation with Pact, Postman, and consumer-driven contract strategies.
|
||||
---
|
||||
|
||||
# ClaudeForge API Contract Tester
|
||||
|
||||
ClaudeForge intelligent API contract testing system that ensures API compatibility, validates contracts between consumers and providers, and maintains backward compatibility through comprehensive consumer-driven contract testing strategies.
|
||||
|
||||
## Purpose
|
||||
|
||||
Transform API testing from manual validation to intelligent automation that ensures contract compliance, prevents breaking changes, and maintains seamless integration between microservices and external consumers.
|
||||
|
||||
## Features
|
||||
|
||||
- **Contract Testing**: Consumer-driven contract testing with Pact and other frameworks
|
||||
- **Schema Validation**: JSON Schema, OpenAPI, and GraphQL schema validation
|
||||
- **API Testing**: Automated REST and GraphQL API testing with comprehensive coverage
|
||||
- **Backward Compatibility**: Detect breaking changes before deployment
|
||||
- **Mock Services**: Generate mock servers from contracts for parallel development
|
||||
- **Contract Publishing**: Centralized contract registry with versioning
|
||||
- **CI/CD Integration**: Seamless integration with continuous deployment pipelines
|
||||
- **Detailed Reporting**: Comprehensive test reports with failure analysis
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
/api-contract-tester [type] [options]
|
||||
```
|
||||
|
||||
Target: $ARGUMENTS (if specified, otherwise analyze current scope)
|
||||
|
||||
### Contract Testing Types
|
||||
|
||||
**Pact Consumer Testing:**
|
||||
```bash
|
||||
/api-contract-tester pact-consumer --service=UserService --provider=AuthAPI
|
||||
```
|
||||
Generates consumer-side Pact tests with:
|
||||
- Consumer expectations definition
|
||||
- Request/response matching rules
|
||||
- State management for test scenarios
|
||||
- Pact file generation for provider verification
|
||||
- Mock provider server for isolated testing
|
||||
- Flexible matching (type, regex, equality)
|
||||
- Header and query parameter validation
|
||||
- JSON body structure verification
|
||||
|
||||
**Pact Provider Testing:**
|
||||
```bash
|
||||
/api-contract-tester pact-provider --service=AuthAPI --contracts=./pacts
|
||||
```
|
||||
Verifies provider against consumer contracts with:
|
||||
- Contract verification against running service
|
||||
- State setup for provider verification
|
||||
- Provider state callbacks implementation
|
||||
- Detailed verification reports
|
||||
- Breaking change detection
|
||||
- Version compatibility checking
|
||||
- Pact broker integration
|
||||
- Automated verification in CI/CD
|
||||
|
||||
**Postman Collection Testing:**
|
||||
```bash
|
||||
/api-contract-tester postman --collection=./api-tests.json --environment=staging
|
||||
```
|
||||
Executes Postman collection tests including:
|
||||
- Environment variable management
|
||||
- Pre-request scripts execution
|
||||
- Response assertions and validation
|
||||
- Test script execution
|
||||
- Collection runner automation
|
||||
- Data-driven testing with CSV/JSON
|
||||
- Authentication flows (OAuth, JWT, API Key)
|
||||
- Chained requests with variable passing
|
||||
|
||||
### Schema Validation
|
||||
|
||||
**OpenAPI Validation:**
|
||||
```bash
|
||||
/api-contract-tester openapi --spec=./openapi.yaml --endpoint=/api/users
|
||||
```
|
||||
Validates API against OpenAPI specification:
|
||||
- Request validation (path, query, body, headers)
|
||||
- Response validation (status, headers, body)
|
||||
- Schema compliance checking
|
||||
- Required field validation
|
||||
- Data type enforcement
|
||||
- Format validation (email, uri, date-time)
|
||||
- Enum value verification
|
||||
- Range and length constraints
|
||||
|
||||
**JSON Schema Validation:**
|
||||
```bash
|
||||
/api-contract-tester json-schema --schema=./user.schema.json --data=./response.json
|
||||
```
|
||||
Performs JSON Schema validation with:
|
||||
- Schema draft version support (draft-07, 2019-09, 2020-12)
|
||||
- Type validation (string, number, object, array)
|
||||
- Required properties enforcement
|
||||
- Additional properties control
|
||||
- Pattern matching with regex
|
||||
- Format validators (email, hostname, ipv4, uuid)
|
||||
- Nested schema validation
|
||||
- Conditional schema application
|
||||
|
||||
**GraphQL Schema Validation:**
|
||||
```bash
|
||||
/api-contract-tester graphql --schema=./schema.graphql --query=./queries/*.graphql
|
||||
```
|
||||
Validates GraphQL queries and mutations:
|
||||
- Query syntax validation
|
||||
- Schema type checking
|
||||
- Field existence verification
|
||||
- Argument type validation
|
||||
- Fragment usage validation
|
||||
- Directive usage verification
|
||||
- Deprecated field detection
|
||||
- Query complexity analysis
|
||||
|
||||
### Consumer-Driven Contract Testing
|
||||
|
||||
**Contract Definition:**
|
||||
```bash
|
||||
/api-contract-tester define-contract --consumer=WebApp --provider=OrderAPI
|
||||
```
|
||||
Creates contract definitions with:
|
||||
- Consumer expectations specification
|
||||
- Request format definition (method, path, headers, body)
|
||||
- Response expectations (status, headers, body)
|
||||
- State preconditions for scenarios
|
||||
- Matching rules for flexible validation
|
||||
- Example values for documentation
|
||||
- Contract versioning strategy
|
||||
- Change log documentation
|
||||
|
||||
**Contract Verification:**
|
||||
```bash
|
||||
/api-contract-tester verify-contract --provider=OrderAPI --version=1.2.0
|
||||
```
|
||||
Verifies provider against contracts including:
|
||||
- All consumer contract verification
|
||||
- State setup for test scenarios
|
||||
- Concurrent verification execution
|
||||
- Detailed mismatch reporting
|
||||
- Version compatibility matrix
|
||||
- Breaking change alerts
|
||||
- Regression detection
|
||||
- Performance benchmarking
|
||||
|
||||
**Contract Publishing:**
|
||||
```bash
|
||||
/api-contract-tester publish --broker=https://pact-broker.example.com --version=1.2.0
|
||||
```
|
||||
Publishes contracts to broker with:
|
||||
- Contract upload to centralized registry
|
||||
- Version tagging and labeling
|
||||
- Branch-specific contracts
|
||||
- Environment deployment tracking
|
||||
- Contract diffing and comparison
|
||||
- Consumer notification on changes
|
||||
- Webhook triggers for CI/CD
|
||||
- Access control and authentication
|
||||
|
||||
### Integration Testing
|
||||
|
||||
**REST API Testing:**
|
||||
```bash
|
||||
/api-contract-tester rest --baseUrl=https://api.example.com --tests=./tests/*.spec.js
|
||||
```
|
||||
Executes REST API tests with:
|
||||
- HTTP method testing (GET, POST, PUT, DELETE, PATCH)
|
||||
- Status code assertions
|
||||
- Response time validation
|
||||
- Header validation
|
||||
- Cookie handling and assertion
|
||||
- Authentication and authorization
|
||||
- Rate limiting verification
|
||||
- Error handling validation
|
||||
- Retry and timeout configuration
|
||||
|
||||
**GraphQL API Testing:**
|
||||
```bash
|
||||
/api-contract-tester graphql --endpoint=https://api.example.com/graphql
|
||||
```
|
||||
Tests GraphQL endpoints including:
|
||||
- Query execution and validation
|
||||
- Mutation testing with side effects
|
||||
- Subscription testing for real-time updates
|
||||
- Error handling and error codes
|
||||
- Partial response handling
|
||||
- Batch query execution
|
||||
- Query performance monitoring
|
||||
- Cache behavior verification
|
||||
|
||||
**Microservice Integration:**
|
||||
```bash
|
||||
/api-contract-tester integration --services=./docker-compose.yml
|
||||
```
|
||||
Performs integration testing with:
|
||||
- Multi-service orchestration
|
||||
- Service dependency management
|
||||
- Contract verification across services
|
||||
- End-to-end workflow testing
|
||||
- Message queue testing
|
||||
- Event-driven architecture validation
|
||||
- Service discovery verification
|
||||
- Circuit breaker testing
|
||||
|
||||
## Code Generation Examples
|
||||
|
||||
### Pact Consumer Test (JavaScript)
|
||||
```javascript
|
||||
const { Pact } = require('@pact-foundation/pact');
|
||||
const { like, eachLike, term } = require('@pact-foundation/pact').Matchers;
|
||||
const path = require('path');
|
||||
|
||||
describe('User Service Consumer', () => {
|
||||
const provider = new Pact({
|
||||
consumer: 'WebApp',
|
||||
provider: 'UserService',
|
||||
port: 8080,
|
||||
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
|
||||
dir: path.resolve(process.cwd(), 'pacts'),
|
||||
logLevel: 'INFO'
|
||||
});
|
||||
|
||||
beforeAll(() => provider.setup());
|
||||
afterEach(() => provider.verify());
|
||||
afterAll(() => provider.finalize());
|
||||
|
||||
describe('GET /users/:id', () => {
|
||||
beforeEach(() => {
|
||||
return provider.addInteraction({
|
||||
state: 'user with ID 123 exists',
|
||||
uponReceiving: 'a request for user 123',
|
||||
withRequest: {
|
||||
method: 'GET',
|
||||
path: '/users/123',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': term({
|
||||
matcher: 'Bearer \\w+',
|
||||
generate: 'Bearer token123'
|
||||
})
|
||||
}
|
||||
},
|
||||
willRespondWith: {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: {
|
||||
id: like(123),
|
||||
username: like('john_doe'),
|
||||
email: term({
|
||||
matcher: '\\S+@\\S+\\.\\S+',
|
||||
generate: 'john@example.com'
|
||||
}),
|
||||
profile: {
|
||||
firstName: like('John'),
|
||||
lastName: like('Doe'),
|
||||
age: like(30)
|
||||
},
|
||||
roles: eachLike('user'),
|
||||
createdAt: term({
|
||||
matcher: '\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}',
|
||||
generate: '2023-01-15T10:30:00'
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('returns user successfully', async () => {
|
||||
const response = await fetch('http://localhost:8080/users/123', {
|
||||
headers: {
|
||||
'Authorization': 'Bearer token123',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
const user = await response.json();
|
||||
expect(user.id).toBe(123);
|
||||
expect(user.email).toMatch(/\S+@\S+\.\S+/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /users', () => {
|
||||
beforeEach(() => {
|
||||
return provider.addInteraction({
|
||||
state: 'no existing user with email john@example.com',
|
||||
uponReceiving: 'a request to create a new user',
|
||||
withRequest: {
|
||||
method: 'POST',
|
||||
path: '/users',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': term({
|
||||
matcher: 'Bearer \\w+',
|
||||
generate: 'Bearer token123'
|
||||
})
|
||||
},
|
||||
body: {
|
||||
username: 'john_doe',
|
||||
email: 'john@example.com',
|
||||
password: like('securePassword123'),
|
||||
profile: {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
}
|
||||
}
|
||||
},
|
||||
willRespondWith: {
|
||||
status: 201,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Location': term({
|
||||
matcher: '/users/\\d+',
|
||||
generate: '/users/123'
|
||||
})
|
||||
},
|
||||
body: {
|
||||
id: like(123),
|
||||
username: 'john_doe',
|
||||
email: 'john@example.com',
|
||||
createdAt: term({
|
||||
matcher: '\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}',
|
||||
generate: '2023-01-15T10:30:00'
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('creates user successfully', async () => {
|
||||
const response = await fetch('http://localhost:8080/users', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer token123'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: 'john_doe',
|
||||
email: 'john@example.com',
|
||||
password: 'securePassword123',
|
||||
profile: { firstName: 'John', lastName: 'Doe' }
|
||||
})
|
||||
});
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.headers.get('Location')).toMatch(/\/users\/\d+/);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Pact Provider Verification (Node.js)
|
||||
```javascript
|
||||
const { Verifier } = require('@pact-foundation/pact');
|
||||
const path = require('path');
|
||||
const server = require('./server');
|
||||
|
||||
describe('User Service Provider', () => {
|
||||
let app;
|
||||
const PORT = 8081;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = await server.listen(PORT);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
it('validates expectations of WebApp', () => {
|
||||
const opts = {
|
||||
provider: 'UserService',
|
||||
providerBaseUrl: `http://localhost:${PORT}`,
|
||||
pactBrokerUrl: 'https://pact-broker.example.com',
|
||||
pactBrokerToken: process.env.PACT_BROKER_TOKEN,
|
||||
publishVerificationResult: true,
|
||||
providerVersion: process.env.GIT_COMMIT,
|
||||
providerVersionBranch: process.env.GIT_BRANCH,
|
||||
consumerVersionSelectors: [
|
||||
{ mainBranch: true },
|
||||
{ deployedOrReleased: true }
|
||||
],
|
||||
stateHandlers: {
|
||||
'user with ID 123 exists': async () => {
|
||||
// Setup: Create user with ID 123 in test database
|
||||
await database.users.create({
|
||||
id: 123,
|
||||
username: 'john_doe',
|
||||
email: 'john@example.com',
|
||||
profile: { firstName: 'John', lastName: 'Doe', age: 30 },
|
||||
roles: ['user'],
|
||||
createdAt: '2023-01-15T10:30:00'
|
||||
});
|
||||
},
|
||||
'no existing user with email john@example.com': async () => {
|
||||
// Setup: Ensure no user exists with this email
|
||||
await database.users.deleteMany({ email: 'john@example.com' });
|
||||
}
|
||||
},
|
||||
beforeEach: async () => {
|
||||
// Clean database before each verification
|
||||
await database.reset();
|
||||
}
|
||||
};
|
||||
|
||||
return new Verifier(opts).verifyProvider();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### OpenAPI Validation (Python)
|
||||
```python
|
||||
from openapi_spec_validator import validate_spec
|
||||
from openapi_core import create_spec
|
||||
from openapi_core.validation.request.validators import RequestValidator
|
||||
from openapi_core.validation.response.validators import ResponseValidator
|
||||
import yaml
|
||||
import requests
|
||||
|
||||
class APIContractTester:
|
||||
def __init__(self, spec_path, base_url):
|
||||
with open(spec_path, 'r') as f:
|
||||
self.spec_dict = yaml.safe_load(f)
|
||||
|
||||
# Validate OpenAPI spec is valid
|
||||
validate_spec(self.spec_dict)
|
||||
|
||||
self.spec = create_spec(self.spec_dict)
|
||||
self.base_url = base_url
|
||||
self.request_validator = RequestValidator(self.spec)
|
||||
self.response_validator = ResponseValidator(self.spec)
|
||||
|
||||
def test_endpoint(self, method, path, headers=None, body=None, expected_status=200):
|
||||
"""Test API endpoint against OpenAPI contract"""
|
||||
|
||||
# Build full URL
|
||||
url = f"{self.base_url}{path}"
|
||||
|
||||
# Validate request against OpenAPI spec
|
||||
request = self._build_request(method, path, headers, body)
|
||||
request_validation = self.request_validator.validate(request)
|
||||
|
||||
if request_validation.errors:
|
||||
raise ValueError(f"Request validation failed: {request_validation.errors}")
|
||||
|
||||
# Make actual HTTP request
|
||||
response = requests.request(method, url, headers=headers, json=body)
|
||||
|
||||
# Validate response against OpenAPI spec
|
||||
openapi_response = self._build_response(response, path, method)
|
||||
response_validation = self.response_validator.validate(openapi_response)
|
||||
|
||||
if response_validation.errors:
|
||||
raise ValueError(f"Response validation failed: {response_validation.errors}")
|
||||
|
||||
# Assert expected status code
|
||||
assert response.status_code == expected_status, \
|
||||
f"Expected {expected_status}, got {response.status_code}"
|
||||
|
||||
return response
|
||||
|
||||
def test_all_endpoints(self):
|
||||
"""Test all endpoints defined in OpenAPI spec"""
|
||||
results = []
|
||||
|
||||
for path, path_item in self.spec_dict['paths'].items():
|
||||
for method, operation in path_item.items():
|
||||
if method in ['get', 'post', 'put', 'delete', 'patch']:
|
||||
try:
|
||||
print(f"Testing {method.upper()} {path}")
|
||||
self.test_endpoint(method.upper(), path)
|
||||
results.append({
|
||||
'path': path,
|
||||
'method': method,
|
||||
'status': 'PASS'
|
||||
})
|
||||
except Exception as e:
|
||||
results.append({
|
||||
'path': path,
|
||||
'method': method,
|
||||
'status': 'FAIL',
|
||||
'error': str(e)
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
def validate_breaking_changes(self, old_spec_path):
|
||||
"""Detect breaking changes between API versions"""
|
||||
with open(old_spec_path, 'r') as f:
|
||||
old_spec = yaml.safe_load(f)
|
||||
|
||||
breaking_changes = []
|
||||
|
||||
# Check for removed endpoints
|
||||
for path in old_spec['paths']:
|
||||
if path not in self.spec_dict['paths']:
|
||||
breaking_changes.append(f"Removed endpoint: {path}")
|
||||
|
||||
# Check for removed operations
|
||||
for path, operations in old_spec['paths'].items():
|
||||
if path in self.spec_dict['paths']:
|
||||
for method in operations:
|
||||
if method not in self.spec_dict['paths'][path]:
|
||||
breaking_changes.append(f"Removed operation: {method.upper()} {path}")
|
||||
|
||||
return breaking_changes
|
||||
|
||||
# Usage example
|
||||
tester = APIContractTester('./openapi.yaml', 'https://api.example.com')
|
||||
results = tester.test_all_endpoints()
|
||||
|
||||
for result in results:
|
||||
print(f"{result['method'].upper()} {result['path']}: {result['status']}")
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Contract Testing Strategy
|
||||
- **Consumer-Driven**: Let consumers define their expectations
|
||||
- **Version Compatibility**: Test against multiple provider versions
|
||||
- **State Management**: Define clear provider states for scenarios
|
||||
- **Matching Flexibility**: Use type matching over exact matching where appropriate
|
||||
- **Regular Verification**: Run provider verification on every deployment
|
||||
|
||||
### CI/CD Integration
|
||||
- **Automated Execution**: Run contract tests in CI pipeline
|
||||
- **Pact Broker**: Use centralized contract registry for collaboration
|
||||
- **Can-I-Deploy**: Check contract compatibility before deployment
|
||||
- **Version Tagging**: Tag contracts with deployment environments
|
||||
- **Webhook Triggers**: Trigger provider verification on consumer changes
|
||||
|
||||
### Schema Validation
|
||||
- **Comprehensive Coverage**: Validate all request/response combinations
|
||||
- **Error Scenarios**: Test error responses and edge cases
|
||||
- **Backward Compatibility**: Detect breaking changes before release
|
||||
- **Documentation Sync**: Keep schemas synchronized with actual API
|
||||
- **Version Strategy**: Maintain multiple schema versions for gradual migration
|
||||
|
||||
### Testing Best Practices
|
||||
- **Isolated Tests**: Each test should be independent
|
||||
- **Fast Execution**: Keep test execution time minimal
|
||||
- **Clear Assertions**: Make test failures easy to understand
|
||||
- **Test Data**: Use realistic test data that covers edge cases
|
||||
- **Mocking Strategy**: Mock external dependencies appropriately
|
||||
|
||||
---
|
||||
|
||||
**ClaudeForge API Contract Tester** - Enterprise-grade API contract testing with consumer-driven strategies, comprehensive validation, and seamless CI/CD integration for reliable microservice architectures.
|
||||
45
plugin.lock.json
Normal file
45
plugin.lock.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||
"pluginId": "gh:claudeforge/marketplace:plugins/commands/api-contract-tester",
|
||||
"normalized": {
|
||||
"repo": null,
|
||||
"ref": "refs/tags/v20251128.0",
|
||||
"commit": "b2e73342b2d6cfd12ff5fbf657d22b27cfb04dd4",
|
||||
"treeHash": "8322dcd2bfa544f5d865294f153ead343b57b605f4867b71060e98955a697f59",
|
||||
"generatedAt": "2025-11-28T10:15:25.292863Z",
|
||||
"toolVersion": "publish_plugins.py@0.2.0"
|
||||
},
|
||||
"origin": {
|
||||
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||
"branch": "master",
|
||||
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "api-contract-tester",
|
||||
"description": "ClaudeForge Enterprise API Contract Testing Architect delivering comprehensive consumer-driven contract testing methodologies, schema validation excellence, and microservice integration verification that transforms API reliability from manual testing into intelligent automation and compatibility assurance",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"content": {
|
||||
"files": [
|
||||
{
|
||||
"path": "README.md",
|
||||
"sha256": "6751f64b1cc1211827de825b9c2aab1b9f49fac7bc92385353b3c3b1ee7f7aad"
|
||||
},
|
||||
{
|
||||
"path": ".claude-plugin/plugin.json",
|
||||
"sha256": "ffa4002b9392a3379d20e13f571e4a127d768af9892284229f9b7637b46e8b2f"
|
||||
},
|
||||
{
|
||||
"path": "commands/api-contract-tester.md",
|
||||
"sha256": "e3b2a5228ccfee30272e515c258b91ce4bfa1b21e01f82f7fd7d8ba29b0b80fc"
|
||||
}
|
||||
],
|
||||
"dirSha256": "8322dcd2bfa544f5d865294f153ead343b57b605f4867b71060e98955a697f59"
|
||||
},
|
||||
"security": {
|
||||
"scannedAt": null,
|
||||
"scannerVersion": null,
|
||||
"flags": []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user