Coletor OpenGraph para BloodHound que mapeia caminhos de ataque de infraestrutura DevOps para MLOps, coletando recursos de pipelines CI/CD, service principals e plataformas de ML para análise de movimento lateral.
Um coletor OpenGraph de prova de conceito para BloodHound que mapeia caminhos de ataque de infraestrutura DevOps para MLOps.
Baseado em Pipelines of Privilege: Attack Paths from DevOps to MLOps Infrastructure por Brett Hawkins (@h4wkst3r).
O Dop2Mop coleta dados de plataformas DevOps e MLOps para identificar caminhos de ataque que permitem movimento lateral de pipelines CI/CD para infraestrutura de treinamento de machine learning. Ele gera JSON OpenGraph compatível com BloodHound para visualização e análise.
| Plataformas DevOps | Plataformas MLOps | Provedores de Identidade |
|---|---|---|
| GitHub (Actions, Repos, Secrets) | Azure Machine Learning | Azure AD Service Principals |
| Azure DevOps (Pipelines, Service Connections) | Amazon SageMaker | AWS IAM Roles OIDC/Federated Identity |
O Dop2Mop modela os cinco limites críticos de confiança identificados na pesquisa:
git clone https://github.com/h4wkst3r/dop2mop.git cd dop2mop pip install -r requirements.txt pip install -e .
## O Que é Coletado
Cada coletor reúne recursos específicos da plataforma e mapeia os limites de confiança entre eles:
| Coletor | Recursos Coletados |
|-----------|-------------------|
| **GitHub** | Organizações, repositórios, fluxos de trabalho, segredos, regras de proteção de branch, configurações OIDC, referências de imagens de contêineres, referências de buckets S3 |
| **Azure DevOps** | Organizações, projetos, pipelines (YAML), conexões de serviço (com detalhes de escopo), grupos de variáveis, pools de agentes, repositórios |
| **Azure ML** | Workspaces, clusters/instâncias de computação, datastores, ambientes de ML, modelos registrados, trabalhos/experimentos, endpoints online e em lote |
| **SageMaker** | Trabalhos de treinamento, modelos, endpoints, domínios, instâncias de notebook, funções de execução IAM (com análise de políticas), repositórios/imagens ECR, buckets S3 (filtrados para relevantes a ML) |
## Início Rápido
### Gerar Dados de Demonstração
A maneira mais rápida de ver o Dop2Mop em ação é gerar dados de demonstração mostrando os cenários de ataque da pesquisa:```bash
dop2mop demo -o demo.json
// Container Image Poisoning (Supply Chain Attack) MATCH p=(workflow)-[:CanPoisonImage]->(image)<-[:PullsImage]-(job) RETURN p
// OIDC/Federated Identity Abuse (confirmed edges) MATCH p=(workflow)-[:OIDCTrust]->(oidc)-[:CanAssumeRole]->(role)-[:SubmitsJob]->(job) RETURN p
// OIDC abuse including inferred paths MATCH p=(workflow)-[:OIDCTrust]->(oidc)-[:InferredCanAssumeRole]->(role) RETURN p
// Dataset Poisoning via Pickle Deserialization MATCH p=(workflow)-[:CanPoisonDataset]->(dataset)<-[:LoadsDataset]-(job) RETURN p
// Find repos with weak/no branch protection (TB1 exploitable) MATCH (repo)-[:BypassesProtection]->(repo) RETURN repo.name, repo.default_branch
// Find overprivileged SageMaker IAM roles MATCH (role:IAMRole) WHERE role.is_admin = true OR role.has_s3_full_access = true RETURN role.name, role.attached_policies
// Find SageMaker notebooks with root + internet access MATCH (nb:SMNotebook) WHERE nb.root_access = 'Enabled' AND nb.direct_internet_access = 'Enabled' RETURN nb.name, nb.status
// Find self-hosted ADO agent pools MATCH (agent:ADOAgent) WHERE agent.is_hosted = false RETURN agent.name, agent.pool_type
---
## Configuração
### Arquivo de Configuração
Em vez de passar credenciais a cada execução, você pode salvá-las em um arquivo de configuração. Copie o exemplo incluído e preencha seus valores:```bash
cp dop2mop.yaml.example dop2mop.yaml
# Edit dop2mop.yaml with your credentials
Dop2Mop verifica estes locais em ordem:
--configdop2mop.yaml / dop2mop.yml / .dop2mop.yaml no diretório atual~/.dop2mop.yamlNota:
dop2mop.yamlestá em.gitignorepara evitar o commit acidental de credenciais. O arquivo de exemplo (dop2mop.yaml.example) é seguro para comitar.
Veja dop2mop.yaml.example para todas as opções disponíveis com comentários.
Ordem de prioridade: argumentos CLI > arquivo de configuração > variáveis de ambiente.
Teste as credenciais antes de executar uma coleta completa:```bash
dop2mop collect --validate -v
dop2mop collect --validate --collectors github,sagemaker -v
Isso faz uma chamada de API leve por plataforma para verificar se os tokens são válidos antes de iniciar a coleta.
### Aliases de Coletores
Você pode usar nomes curtos em vez de nomes de classes completos com `--collectors`:
| Alias | Coletor |
|-------|-----------|
| `github`, `gh` | GitHubCollector |
| `ado`, `azuredevops`, `azure-devops` | AzureDevOpsCollector |
| `azureml`, `azure-ml` | AzureMLCollector |
| `sagemaker`, `sm` | SageMakerCollector |```bash
# These are equivalent:
dop2mop collect --collectors GitHubCollector,SageMakerCollector
dop2mop collect --collectors github,sagemaker
dop2mop collect --collectors gh,sm
dop2mop [options]
Commands: collect Collect data from DevOps/MLOps platforms demo Generate demo data with attack scenarios
### Opções Globais
| Opção | Descrição |
|--------|-------------|
| `-v, --verbose` | Ativar saída detalhada (logging no nível INFO) |
| `--debug` | Ativar saída de depuração (logging no nível DEBUG) |
---
### `dop2mop collect`
Coletar dados das plataformas DevOps e MLOps configuradas.```bash
dop2mop collect [OPTIONS]
| Opção | Descrição |
|---|---|
-o, --output FILE | Caminho do arquivo de saída (padrão: dop2mop_output.json) |
--zip | Comprimir saída para arquivo ZIP |
--config FILE | Caminho para arquivo de configuração YAML/JSON |
--validate | Validar credenciais antes da coleta |
--collectors LIST | Lista separada por vírgulas de coletores ou aliases (ex.: github,sm) |
--max-items N | Número máximo de itens a coletar por tipo |
--no-secrets | Pular enumeração de segredos/credenciais |
| Opção | Descrição |
|---|---|
--github-token TOKEN | Token de acesso pessoal do GitHub |
--github-org ORG | Nome da organização do GitHub |
--github-enterprise-url URL | URL do GitHub Enterprise Server |
| Opção | Descrição |
|---|---|
--azure-devops-token TOKEN | Token de acesso pessoal do Azure DevOps (PAT) |
--azure-devops-access-token TOKEN | Token de acesso do Azure DevOps (autenticação Bearer, opcional) |
--azure-devops-org ORG | Nome da organização do Azure DevOps |
| Opção | Descrição |
|---|---|
--azure-subscription-id ID | ID da assinatura do Azure |
--azure-tenant-id ID | ID do inquilino do Azure AD |
--azure-client-id ID | ID do cliente do principal de serviço (opcional) |
--azure-client-secret SECRET | Segredo do cliente do principal de serviço (opcional) |
--azure-access-token TOKEN | Token de acesso do Azure para autenticação no Azure ML (opcional) |
| Opção | Descrição |
|---|---|
--aws-access-key-id KEY | ID da chave de acesso AWS |
--aws-secret-access-key SECRET | Chave de acesso secreta AWS |
--aws-region REGION | Região AWS (padrão: us-east-1) |
--aws-profile PROFILE | Nome do perfil da AWS CLI |
| Nome do Coletor | Plataforma | Credenciais Necessárias |
|---|---|---|
GitHubCollector | GitHub | --github-token, --github-org |
AzureDevOpsCollector | Azure DevOps | --azure-devops-token ou --azure-devops-access-token, --azure-devops-org |
AzureMLCollector | Azure ML | --azure-subscription-id, --azure-tenant-id |
SageMakerCollector | AWS SageMaker | --aws-profile ou --aws-access-key-id |
dop2mop demoGerar dados de demonstração mostrando os quatro cenários de ataque da pesquisa.```bash dop2mop demo [OPTIONS]
| Opção | Descrição |
|--------|-------------|
| `-o, --output FILE` | Caminho do ficheiro de saída (padrão: `dop2mop_demo.json`) |
---
### `dop2mop icons`
Gerar configuração personalizada de ícones para os tipos de nó do BloodHound.```bash
dop2mop icons [OPTIONS]
| Opção | Descrição |
|---|---|
-o, --output FILE | Caminho do arquivo de saída (padrão: dop2mop_icons.json) |
dop2mop collect -o output.json
dop2mop collect --config dop2mop.yaml -o output.json -v
dop2mop collect --validate -o output.json -v
dop2mop collect -o output.json -v
dop2mop collect -o output.json --debug
dop2mop collect -o output.json --zip
dop2mop collect --max-items 100 -o output.json
dop2mop collect --no-secrets -o output.json
### Coleção de Plataforma Única```bash
# GitHub only (aliases: github, gh)
dop2mop collect --collectors github -o github.json -v
# Azure DevOps only (aliases: ado, azuredevops)
dop2mop collect --collectors ado -o ado.json -v
# Azure ML only (aliases: azureml, azure-ml)
dop2mop collect --collectors azureml -o azureml.json -v
# SageMaker only (aliases: sagemaker, sm)
dop2mop collect --collectors sm -o sagemaker.json -v
dop2mop collect --collectors github,sagemaker -o output.json -v
dop2mop collect --collectors github,ado -o output.json -v
dop2mop collect --collectors ado,azureml -o azure.json -v
dop2mop collect --collectors github,ado,azureml,sagemaker -o full.json -v
### Exemplos de Coleções do GitHub```bash
# Using environment variables
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"
export GITHUB_ORG="your-org"
dop2mop collect --collectors GitHubCollector -o github.json -v
# Using command-line arguments
dop2mop collect --collectors GitHubCollector \
--github-token ghp_xxxxxxxxxxxx \
--github-org your-org \
-o github.json -v
# GitHub Enterprise Server
dop2mop collect --collectors GitHubCollector \
--github-token ghp_xxxxxxxxxxxx \
--github-org your-org \
--github-enterprise-url https://github.yourcompany.com/api/v3 \
-o github.json -v
# Skip secret enumeration
dop2mop collect --collectors GitHubCollector \
--github-token ghp_xxxxxxxxxxxx \
--github-org your-org \
--no-secrets \
-o github.json -v
# Limit to 50 repositories
dop2mop collect --collectors GitHubCollector \
--github-token ghp_xxxxxxxxxxxx \
--github-org your-org \
--max-items 50 \
-o github.json -v
export AZURE_DEVOPS_TOKEN="your-pat" export AZURE_DEVOPS_ORG="your-org" dop2mop collect --collectors AzureDevOpsCollector -o ado.json -v
dop2mop collect --collectors AzureDevOpsCollector
--azure-devops-token your-pat
--azure-devops-org your-org
-o ado.json -v
dop2mop collect --collectors AzureDevOpsCollector
--azure-devops-access-token eyJ0...
--azure-devops-org your-org
-o ado.json -v
> **Nota:** Prioridade de autenticação do Azure DevOps: access token (Bearer) > PAT (Basic).
> Tokens de acesso podem ser obtidos via `az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798`.
### Exemplos de Coleções do Azure ML```bash
# Using environment variables
export AZURE_SUBSCRIPTION_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export AZURE_TENANT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
dop2mop collect --collectors AzureMLCollector -o azureml.json -v
# Using DefaultAzureCredential (az login)
dop2mop collect --collectors AzureMLCollector \
--azure-subscription-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--azure-tenant-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
-o azureml.json -v
# Using Service Principal
dop2mop collect --collectors AzureMLCollector \
--azure-subscription-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--azure-tenant-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--azure-client-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--azure-client-secret your-secret \
-o azureml.json -v
# Using Access Token
dop2mop collect --collectors AzureMLCollector \
--azure-subscription-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--azure-tenant-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--azure-access-token eyJ0... \
-o azureml.json -v
Nota: Prioridade de autenticação do Azure ML: token de acesso > principal de serviço > DefaultAzureCredential (az login). Tokens de acesso podem ser obtidos via
az account get-access-token --resource https://management.azure.com/.
export AWS_PROFILE="your-profile" dop2mop collect --collectors SageMakerCollector -o sagemaker.json -v
dop2mop collect --collectors SageMakerCollector
--aws-profile your-profile
-o sagemaker.json -v
dop2mop collect --collectors SageMakerCollector
--aws-access-key-id AKIAXXXXXXXXXXXXXXXX
--aws-secret-access-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--aws-region us-east-1
-o sagemaker.json -v
dop2mop collect --collectors SageMakerCollector
--aws-profile your-profile
--aws-region us-west-2
-o sagemaker.json -v
### Coleção Completa de Ambiente```bash
# Set all environment variables
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"
export GITHUB_ORG="your-org"
export AZURE_DEVOPS_TOKEN="your-pat"
export AZURE_DEVOPS_ORG="your-org"
export AZURE_SUBSCRIPTION_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export AZURE_TENANT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export AWS_PROFILE="your-profile"
# Collect from all platforms (auto-detects configured collectors)
dop2mop collect -o full_collection.json -v
# Or with explicit collectors
dop2mop collect \
--collectors GitHubCollector,AzureDevOpsCollector,AzureMLCollector,SageMakerCollector \
-o full_collection.json -v
Todas as opções de linha de comando podem ser definidas por variáveis de ambiente:
| Variável de Ambiente | Equivalente CLI | Descrição |
|---|---|---|
GITHUB_TOKEN | --github-token | Token de acesso pessoal do GitHub |
GITHUB_ORG | --github-org | Nome da organização no GitHub |
GITHUB_ENTERPRISE_URL | --github-enterprise-url | URL do GitHub Enterprise Server |
AZURE_DEVOPS_TOKEN | --azure-devops-token | PAT do Azure DevOps |
AZURE_DEVOPS_ACCESS_TOKEN | --azure-devops-access-token | Token de acesso do Azure DevOps (Bearer) |
AZURE_DEVOPS_ORG | --azure-devops-org | Organização do Azure DevOps |
AZURE_SUBSCRIPTION_ID | --azure-subscription-id | ID da assinatura do Azure |
AZURE_TENANT_ID | --azure-tenant-id | ID do tenant do Azure AD |
AZURE_CLIENT_ID | --azure-client-id | ID do cliente do service principal do Azure |
AZURE_CLIENT_SECRET | --azure-client-secret | Segredo do service principal do Azure |
AZURE_ACCESS_TOKEN | --azure-access-token | Token de acesso do Azure para Azure ML |
AWS_ACCESS_KEY_ID | --aws-access-key-id | ID da chave de acesso AWS |
AWS_SECRET_ACCESS_KEY | --aws-secret-access-key | Chave de acesso secreta AWS |
AWS_REGION | --aws-region | Região AWS (padrão: us-east-1) |
AWS_PROFILE | --aws-profile | Nome do perfil AWS CLI |
Prioridade: argumentos CLI > arquivo de configuração > variáveis de ambiente.
| Tipo | Descrição |
|---|---|
GHOrganization | Organização do GitHub |
GHRepository | Repositório do GitHub |
GHWorkflow | Fluxo de trabalho do GitHub Actions |
GHSecret | Segredo do GitHub Actions |
ADOOrganization | Organização do Azure DevOps |
ADOProject | Projeto do Azure DevOps |
ADOPipeline | Pipeline do Azure DevOps |
ADOServiceConnection | Conexão de serviço do Azure DevOps (NHI) com detalhes de escopo |
ADOAgent | Pool de agentes do Azure DevOps (hospedado ou auto-hospedado) |
ADOVariableGroup | Grupo de variáveis do Azure DevOps |
| Tipo | Descrição |
|---|---|
AzMLWorkspace | Workspace do Azure ML |
AzMLCompute | Cluster/instância de computação do Azure ML |
AzMLExperiment | Job/experimento do Azure ML |
AzMLDatastore | Datastore do Azure ML |
AzMLEnvironment | Ambiente do Azure ML (definição de contêiner) |
AzMLModel | Modelo registrado do Azure ML |
SMDomain | Domínio do SageMaker Studio |
SMTrainingJob | Job de treinamento do SageMaker |
SMModel | Modelo do SageMaker |
SMEndpoint | Endpoint do SageMaker (também usado para endpoints do Azure ML) |
SMNotebook | Instância de notebook do SageMaker |
| Tipo | Descrição |
|---|---|
ServicePrincipal | Service principal do Azure AD |
IAMRole | Função IAM da AWS |
OIDCIdentity | Identidade federada OIDC |
ManagedIdentity | Identidade gerenciada do Azure |
| Tipo | Descrição |
|---|---|
ContainerRegistry | Registro de contêineres (ECR, ACR) |
ContainerImage | Imagem de contêiner |
S3Bucket | Bucket S3 da AWS |
Dataset | Dataset de ML |
| Tipo | Limite de Confiança | Descrição |
|---|---|---|
TriggersPipeline | TB1 | Commit de código dispara CI/CD |
HasBranchProtection | TB1 | Repositório possui regras de proteção de branch |
BypassesProtection | TB1 | Proteção de branch fraca/ausente (explorável) |
AuthenticatesAs | TB2 | Pipeline usa service principal |
CanAssumeRole | TB2 | Identidade OIDC pode assumir função IAM |
OIDCTrust | TB2 | Fluxo de trabalho usa federação OIDC |
UsesServiceConnection | TB2 | Pipeline usa conexão de serviço ADO |
PullsImage | TB3 | Job de treinamento puxa imagem de contêiner |
CanPoisonImage | TB3 | Pipeline pode modificar imagem de contêiner |
SubmitsJob | TB4 | Service principal submete job de ML |
CodeExecution | TB4 | Job executa código na computação |
LoadsDataset | TB5 | Job de treinamento carrega dataset |
CanPoisonDataset | TB5 | Pipeline pode modificar dataset |
Deserializes | TB5 | Desserialização insegura |
Estas arestas são criadas por análise heurística quando dados explícitos de API não estão disponíveis (ex.: ARNs de funções armazenados em segredos). Usam tipos de aresta distintos para que possa filtrá-las nas consultas do BloodHound.
| Tipo | Descrição |
|---|---|
InferredCanAssumeRole | Identidade OIDC pode ser capaz de assumir função (inferido) |
InferredSubmitsJob | Fluxo de trabalho pode submeter job de treinamento via OIDC (inferido) |
InferredPullsImage | Job de treinamento pode puxar imagem de contêiner envenenada (inferido) |
InferredLoadsDataset | Job de treinamento pode carregar dataset envenenado (inferido) |
| Tipo | Descrição |
|---|---|
Contains | Relação pai-filho |
MemberOf | Associação a grupo |
HasAccessTo | Permissão para acessar recurso |
HasExecutionRole | Recurso usa uma função de execução IAM |
Owns | Relação de propriedade |
Consulte queries/dop2mop_queries.cypher para exemplos completos de consultas.
O Dop2Mop inclui um arquivo de ícones pré-configurado para tipos de nó personalizados do BloodHound em data/custom_icons.json.
custom_icons.jsonPrimeiro, crie um token de API no BloodHound:
Em seguida, use este script Python para enviar:
# Install the BloodHound SDK
# pip install bloodhound
from bloodhound import BloodHound
import json
# Initialize client with HMAC auth
bh = BloodHound(
base_url="http://localhost:8080",
token_id="your_token_id",
token_key="your_token_key"
)
# Load custom icons
with open("data/custom_icons.json") as f:
icons = json.load(f)
# Upload custom icons
response = bh.custom_nodes.upload(icons)
print(response)
``````python
#!/usr/bin/env python3
"""Upload custom icons to BloodHound CE using HMAC authentication."""
import base64
import hashlib
import hmac
import json
from datetime import datetime, timezone
import requests
# Configuration
BLOODHOUND_URL = "http://localhost:8080"
TOKEN_ID = "your-token-id"
TOKEN_KEY = "your-token-key"
ICONS_FILE = "custom_icons.json"
def hmac_auth(method: str, uri: str, body: bytes = b"") -> dict:
"""Generate HMAC authentication headers."""
digester = hmac.new(
base64.b64decode(TOKEN_KEY),
msg=None,
digestmod=hashlib.sha256
)
now = datetime.now(timezone.utc)
timestamp = now.strftime("%Y-%m-%dT%H:%M:%SZ")
digester.update(f"{method}".encode())
digester.update(f"{uri}".encode())
digester.update(timestamp.encode())
if body:
digester.update(body)
signature = base64.b64encode(digester.digest()).decode()
return {
"Authorization": f"bhesignature {TOKEN_ID}",
"RequestDate": timestamp,
"Signature": signature,
"Content-Type": "application/json",
}
def upload_icons():
"""Upload custom icons to BloodHound."""
uri = "/api/v2/custom-nodes"
url = f"{BLOODHOUND_URL}{uri}"
with open(ICONS_FILE, "rb") as f:
body = f.read()
headers = hmac_auth("POST", uri, body)
response = requests.post(url, headers=headers, data=body)
print(f"Status: {response.status_code}")
print(f"Response: {response.text}")
return response.status_code == 200
if __name__ == "__main__":
upload_icons()
Obtenha um JWT da aba Network do DevTools do seu navegador enquanto estiver logado no BloodHound:```bash
curl -X POST http://localhost:8080/api/v2/custom-nodes
-H "Authorization: Bearer eyJ..."
-H "Content-Type: application/json"
-d @custom_icons.json
## Python API```python
from dop2mop import Dop2MopCollector, CollectorConfig
# Configure collection
config = CollectorConfig(
github_token="ghp_xxx",
github_org="myorg",
aws_profile="default",
)
# Validate credentials first
collector = Dop2MopCollector(config)
results = collector.validate_all()
print(results) # {'GitHubCollector': True, 'SageMakerCollector': True, ...}
# Run collection (supports aliases)
collector.run(collectors=["github", "sm"])
# Save output
collector.save("output.json")
# Get statistics
print(collector.get_stats())
# Get per-collector failure/skip details
print(collector.get_collection_summary())
from dop2mop import CollectorConfig, GitHubCollector, SageMakerCollector from dop2mop.graph import OpenGraphBuilder
builder = OpenGraphBuilder(source_kind="MLOpsBase")
config = CollectorConfig( github_token="ghp_xxx", github_org="myorg", aws_profile="default", )
github = GitHubCollector(config, builder) github.collect()
sagemaker = SageMakerCollector(config, builder) sagemaker.collect()
builder.save("combined.json")
### Construindo Gráficos Personalizados```python
from dop2mop.graph import OpenGraphBuilder
from dop2mop.models import NodeKind, EdgeType
builder = OpenGraphBuilder(source_kind="CustomSource")
# Add nodes
builder.create_node(
id="my-pipeline",
kinds=[NodeKind.AZURE_DEVOPS_PIPELINE.value],
name="My Pipeline",
displayname="Production Pipeline",
)
builder.create_node(
id="my-ml-workspace",
kinds=[NodeKind.AZURE_ML_WORKSPACE.value],
name="ML Workspace",
displayname="Training Workspace",
)
# Add edge
builder.create_edge(
start_id="my-pipeline",
end_id="my-ml-workspace",
kind=EdgeType.SUBMITS_JOB,
properties={"trust_boundary": "TB4"}
)
# Export
builder.save("custom_graph.json")
Sempre comece com a validação de credenciais para detectar problemas de autenticação precocemente.```bash dop2mop collect --validate --collectors github,sm -v
A saída mostrará OK/FAILED por coletor antes do início de qualquer coleta.
### Resumo da Coleta
Após cada execução, o Dop2Mop imprime um resumo mostrando o que foi coletado e o que falhou:```
============================================================
Dop2Mop Collection Summary
============================================================
Total Nodes: 142
DevOps: 45
MLOps: 38
Identity: 12
Artifact: 47
Total Edges: 201
Contains: 62
TriggersPipeline: 15
...
────────────────────────────────────────────────────────
Collection Issues:
GitHubCollector: 45 collected, 3 failed, 1 skipped
FAIL: branch_protection:org/repo - 404 Not Found
SKIP: branch_protection:org/private - Insufficient permissions
Output: output.json
============================================================
"Coletor GitHub não configurado, ignorando"
GITHUB_TOKEN e GITHUB_ORG estão definidas, ou passe --github-token e --github-org"Coletor Azure ML não configurado, ignorando"
AZURE_SUBSCRIPTION_ID e AZURE_TENANT_ID estão definidasaz login se estiver usando DefaultAzureCredential--azure-access-token com um token válido de az account get-access-token"Coletor SageMaker não configurado, ignorando"
AWS_PROFILE ou ambos AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEYProteção de branch retorna 403
Limitação de taxa (erros 429)
--max-items para reduzir chamadas de APINenhum resultado no console Cypher do BloodHound
RETURN a, b) e não propriedades (RETURN a.name, b.name)Filtrando arestas inferidas vs. coletadas
InferredCanAssumeRole em vez de CanAssumeRole)MATCH p=()-[:CanAssumeRole]->() RETURN pMATCH p=()-[:InferredCanAssumeRole]->() RETURN pLicença MIT - Consulte LICENSE para detalhes.