From f63b39df1e7fc4f28879025fe4105a2912fba0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 16 Apr 2026 08:36:51 +0200 Subject: [PATCH 1/8] =?UTF-8?q?Adiciona=20CLAUDE.md=20com=20guia=20para=20?= =?UTF-8?q?automa=C3=A7=C3=A3o=20e=20contribui=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inclui o arquivo CLAUDE.md com orientações detalhadas para uso do Claude Code no repositório. O documento cobre visão geral do projeto, comandos de build, testes, execução da API, uso de Docker, geração de SDKs, arquitetura dos diretórios, pontos de extensibilidade, convenções de código (com nomes em português) e estratégia de branches baseada em GitHub Flow. Facilita a colaboração, automação e padronização no desenvolvimento do toolkit de reconciliação bancária. --- CLAUDE.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ec15fce --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,78 @@ +# CLAUDE.md + +Este ficheiro fornece orientação ao Claude Code (claude.ai/code) quando trabalha com o código neste repositório. + +## Sobre o Projecto + +Toolkit .NET 10 open-source para reconciliação bancária em sistemas ERP moçambicanos. Publicado como pacotes NuGet (`Simansoft.BridgeBank.*`) e imagem Docker. Expõe também uma API REST com SDKs gerados para Python, TypeScript e Java. + +## Comandos + +```bash +# Compilar +dotnet build + +# Testes +dotnet test +dotnet test tests/BridgeBank.Core.Tests # projecto específico +dotnet test --collect:"XPlat Code Coverage" # com cobertura + +# Executar a API +dotnet run --project src/BridgeBank.Api +# http://localhost:8080 — API +# http://localhost:8080/scalar/v1 — documentação interactiva +# http://localhost:8080/openapi/v1.json — especificação OpenAPI + +# Docker +docker compose up --build + +# Regenerar SDKs (após alterar a API) +pwsh scripts/generate-sdks.ps1 # Windows +./scripts/generate-sdks.sh # Linux/macOS +``` + +## Arquitectura + +``` +src/ +├── BridgeBank.Core/ # Motor de reconciliação, classificador, modelos de domínio +├── BridgeBank.Parsers/ # Leitores de extractos bancários (Excel via NPOI) +├── BridgeBank.Generators/ # Geradores de ficheiros de pagamento (TXT, CSV, XML) +├── BridgeBank.ML/ # Classificação e reconciliação com ML.NET +└── BridgeBank.Api/ # Minimal API ASP.NET Core (Scalar + OpenAPI) +sdks/ # Clientes tipados gerados por Kiota (Python, TypeScript, Java) +openapi/ # Especificação OpenAPI gerada automaticamente no build +``` + +- **`BridgeBank.Core`** — Núcleo sem dependências externas, compatível com AOT. Contém `MotorReconciliacao`, `ClassificadorTransacao` e as interfaces de extensibilidade. +- **`BridgeBank.Parsers`** — Cada banco tem a sua implementação em `Bancos/`, estendendo `LeitorExcelBase`. +- **`BridgeBank.Generators`** — Cada banco tem a sua implementação em `Bancos/`, implementando `IGeradorFicheiroPagamento`. +- **`BridgeBank.ML`** — Liga-se ao Core via `IRegraClassificacao`. Pode treinar com dados sintéticos. +- **`BridgeBank.Api`** — Gera a especificação OpenAPI em `openapi/` durante o build. Os SDKs são gerados a partir daí. + +### Pontos de Extensibilidade +- Nova estratégia de correspondência → implementar `IEstrategiaCorrespondencia` +- Nova regra de classificação → implementar `IRegraClassificacao` +- Novo banco (leitor) → estender `LeitorExcelBase` e implementar `ILeitorExtrato` +- Novo banco (gerador) → implementar `IGeradorFicheiroPagamento` + +## Convenções de Código + +- **Classes e métodos**: PascalCase em **português** (ex: `MotorReconciliacao`, `ReconciliarTransacoes`) +- **Variáveis locais**: camelCase em **português** (ex: `transacaoBancaria`) +- **Projectos e namespaces**: PascalCase em **inglês** (ex: `Simansoft.BridgeBank.Core`) +- Nullable reference types e `ImplicitUsings` activos + +## Estratégia de Branches + +GitHub Flow — todo o trabalho entra em `main` via Pull Request: + +``` +main (protegido) + ├── feature/* + ├── fix/* + ├── docs/* + └── chore/* +``` + +Tags `v*.*.*` em `main` disparam publicação automática no NuGet e Docker Hub. From 7e42664e2484678f87e7781dac1a7ad424bfa97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 16 Apr 2026 08:52:04 +0200 Subject: [PATCH 2/8] =?UTF-8?q?Adiciona=20pol=C3=ADticas=20de=20seguran?= =?UTF-8?q?=C3=A7a=20e=20automa=C3=A7=C3=A3o=20de=20depend=C3=AAncias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SECURITY.md: Guia completo de segurança com procedimentos de divulgação responsável, boas práticas para dados sensíveis, validação de entrada e conformidade regulatória - .github/dependabot.yml: Configuração de automação Dependabot para monitorar dependências NuGet, Docker e GitHub Actions com agrupamento inteligente Co-Authored-By: Claude Opus 4.6 --- .github/dependabot.yml | 81 +++++++++++ SECURITY.md | 322 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 SECURITY.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9e5914b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,81 @@ +# Configuração do Dependabot +# Documentação: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates + +version: 2 +updates: + # Monitorar dependências NuGet (.NET) + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "03:00" + timezone: "Africa/Maputo" + # Agrupar atualizações para reduzir número de PRs + groups: + dependency-type: + patterns: + - "dependency-type:production" + - "dependency-type:development" + open-pull-requests-limit: 10 + pull-request-branch-name: + separator: "/" + reviewers: + - "SimansoftMZ/maintainers" + labels: + - "dependencies" + - "chore" + # Auto-merge para patches e minor versions + allow: + - dependency-type: "development" + - dependency-type: "indirect" + # Ignorar versões pré-lançamento + ignore: + - dependency-name: "*" + versions: ["*-*"] + # Ativar commit signing se configurado + commit-message: + prefix: "chore(deps):" + include: "scope" + + # Monitorar dependências Docker + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "04:00" + timezone: "Africa/Maputo" + open-pull-requests-limit: 5 + pull-request-branch-name: + separator: "/" + reviewers: + - "SimansoftMZ/maintainers" + labels: + - "dependencies" + - "docker" + - "chore" + commit-message: + prefix: "chore(docker):" + include: "scope" + + # Monitorar GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "05:00" + timezone: "Africa/Maputo" + open-pull-requests-limit: 5 + pull-request-branch-name: + separator: "/" + reviewers: + - "SimansoftMZ/maintainers" + labels: + - "dependencies" + - "github-actions" + - "chore" + commit-message: + prefix: "chore(actions):" + include: "scope" diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..0a666f0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,322 @@ +# Política de Segurança + +Este documento descreve as práticas de segurança, procedimentos de divulgação responsável e orientações para mitigar riscos ao utilizar o BridgeBank. + +## Reportar Vulnerabilidades + +Se descobrir uma vulnerabilidade de segurança, **não abra uma issue pública no GitHub**. Em vez disso, reporte-a de forma confidencial através de um dos seguintes canais: + +### Via GitHub Security Advisory + +1. Aceda a [GitHub Security Advisory](https://github.com/SimansoftMZ/BridgeBank/security/advisories) +2. Clique em **"Report a vulnerability"** +3. Descreva a vulnerabilidade com detalhes técnicos + +### Via Email (Segurança) + +Envie um email para a equipa de segurança do projecto com: + +- Descrição clara da vulnerabilidade +- Passos para reproduzir +- Impacto potencial +- Versões afectadas +- Sugestões de correcção (se possível) + +**A segurança é uma prioridade — as vulnerabilidades reportadas serão tratadas com urgência.** + +## Processo de Divulgação + +1. **Recepção:** Acknowledgeamos a recepção do relatório dentro de 48 horas +2. **Avaliação:** A equipa avalia a vulnerabilidade e o seu impacto +3. **Correcção:** Desenvolvemos uma correcção em segredo numa branch privada +4. **Teste:** A correcção é validada e testada completamente +5. **Release:** Uma nova versão é publicada com a correcção +6. **Divulgação:** Um CVE (Common Vulnerabilities and Exposures) é atribuído, se aplicável +7. **Comunicação:** O relatório original recebe crédito (a menos que prefira anonimato) + +**Prazo esperado:** 30 dias entre a reportação e a divulgação pública. + +## Responsabilidades de Segurança + +### Utilizadores da Biblioteca + +Ao utilizar o BridgeBank, é responsabilidade sua: + +- **Manter dependências atualizadas** — Configure alertas de segurança do GitHub (Dependabot) +- **Validar dados de entrada** — O BridgeBank processa dados bancários; sempre valide ficheiros e entrada do utilizador +- **Proteger credenciais** — Nunca inclua tokens de API, senhas ou chaves de acesso no controlo de versão +- **Usar HTTPS em produção** — Se utilizar a API REST, sempre use conexões encriptadas +- **Auditar acessos** — Quem tem acesso aos dados processados pelo BridgeBank? + +### Utilizadores da API REST + +Se executar a API REST em produção: + +- **Autenticação e Autorização** — Configure controles de acesso (ex: OAuth 2.0, JWT) +- **Limite de Taxa** — Implemente rate limiting para prevenir abuso +- **HTTPS/TLS** — Use certificados SSL/TLS válidos +- **Validação de Upload** — A API aceita uploads de ficheiros — valide tipo, tamanho e conteúdo +- **Monitoramento** — Monitore logs e métricas para atividade suspeita + +### Contribuidores + +Se contribuir para o projecto: + +- **Não envie segredos** — Revise seus commits antes de push; evite expor chaves, tokens ou dados sensíveis +- **Testes de segurança** — Teste casos extremos e entrada malformada +- **Dependências** — Use versões knowns de bibliotecas; revise `csproj` para dependências desatualizadas +- **Code review** — Aceite feedback crítico sobre segurança + +## Responsabilidades de Segurança do Projecto + +A Simansoft é responsável por: + +- **Auditar dependências regularmente** — Verificar vulnerabilidades conhecidas +- **Aplicar patches** — Corrigir vulnerabilidades reportadas rapidamente +- **Comunicar riscos** — Publicar avisos de segurança quando necessário +- **Revisar código** — Validar mudanças antes do merge +- **Testes de segurança** — Executar testes de segurança estática (SAST) na CI/CD + +## Problemas de Segurança Conhecidos + +Não há vulnerabilidades conhecidas no momento da última atualização. Consulte as [GitHub Security Advisories](https://github.com/SimansoftMZ/BridgeBank/security/advisories) para informações atualizadas. + +## Boas Práticas para Dados Sensíveis + +### Extractos Bancários + +- **Armazenamento** — Criptografe ficheiros de extracto em repouso (ex: AES-256) +- **Transmissão** — Use HTTPS/TLS ao enviar extractos para a API +- **Logs** — Não registre IBANs, números de contas ou valores sensíveis em logs +- **Temporário** — Delete ficheiros extracto após processamento + +### Números de Contas Bancárias + +- **Validação** — Valide o formato (ex: IBAN) antes de processar +- **Mascaramento** — Nos logs/UI, mostre apenas os últimos 4 dígitos +- **Encriptação** — Criptografe dados sensíveis em repouso e em trânsito + +### Transacções + +- **Acesso mínimo** — Apenas utilizadores autenticados acedem a dados de transacção +- **Auditoria** — Registre quem acedeu a que dados e quando +- **Retenção** — Defina políticas de retenção de dados (ex: apagar após 7 anos) + +## Autenticação na API + +A API REST não impõe autenticação por padrão. **Para produção, configure:** + +```csharp +// Exemplo: Adicionar autenticação JWT na API +builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.Authority = "https://seu-provedor-identidade.com"; + options.Audience = "bridgebank-api"; + }); + +app.UseAuthentication(); +app.UseAuthorization(); +``` + +## Validação de Entrada + +O BridgeBank processa ficheiros Excel e JSON. Implemente validações: + +```csharp +// Validar tamanho do ficheiro +const long maxFileSize = 10 * 1024 * 1024; // 10 MB +if (file.Length > maxFileSize) + throw new InvalidOperationException("Ficheiro demasiado grande"); + +// Validar tipo MIME +var allowedTypes = new[] { "application/vnd.ms-excel", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }; +if (!allowedTypes.Contains(file.ContentType)) + throw new InvalidOperationException("Tipo de ficheiro não permitido"); + +// Validar conteúdo +var extrato = leitor.LerExtrato(file.FileName); +if (extrato?.Transacoes == null || !extrato.Transacoes.Any()) + throw new InvalidOperationException("Extracto vazio ou inválido"); +``` + +## Gestão de Dependências + +O BridgeBank utiliza as seguintes dependências principais: + +| Dependência | Versão | Propósito | Risco | +|------------|--------|----------|-------| +| `NPOI` | ≥ 2.6.0 | Leitura de ficheiros Excel | ⚠️ Atualizar regularmente | +| `ML.NET` | ≥ 4.0.0 | Classificação com ML | ⚠️ Auditar modelos | +| `SharpCompress` | (if used) | Compressão | ⚠️ Vulnerabilidades conhecidas — usar `System.IO.Compression` | + +**Recomendação:** Configure [Dependabot](https://github.com/SimansoftMZ/BridgeBank/security/dependabot) no GitHub para alertas automáticos. + +## Testes de Segurança + +Para testar a segurança localmente: + +```bash +# Análise estática de código (usando Roslyn Analyzers) +dotnet build /p:EnforceCodeStyleInBuild=true + +# Verificar dependências vulneráveis +dotnet list package --vulnerable + +# Executar testes com inputs malformados +dotnet test tests/BridgeBank.Core.Tests --filter "Security" +``` + +## Encriptação em Trânsito + +Se utilizar a API REST, configure HTTPS obrigatório: + +```csharp +// Program.cs +app.UseHsts(); // HTTP Strict-Transport-Security +app.UseHttpsRedirection(); + +// Certificado SSL (produção) +// Use um certificado válido, ex: Let's Encrypt +``` + +No Docker: + +```yaml +# docker-compose.yml +services: + api: + environment: + - ASPNETCORE_HTTPS_PORT=443 + - ASPNETCORE_URLS=https://+:443;http://+:80 + ports: + - "443:443" + volumes: + - ./certs:/https:ro # Montar certificados +``` + +## Criptografia em Repouso + +Para dados bancários em repouso: + +```csharp +using System.Security.Cryptography; +using System.Text; + +public class CriptografiaDados +{ + public static string Encriptar(string dados, byte[] chave) + { + using var aes = Aes.Create(); + aes.Key = chave; + aes.GenerateIV(); + + using var encryptor = aes.CreateEncryptor(); + using var ms = new MemoryStream(); + ms.Write(aes.IV, 0, aes.IV.Length); + using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) + { + cs.Write(Encoding.UTF8.GetBytes(dados)); + } + + return Convert.ToBase64String(ms.ToArray()); + } +} +``` + +## Logs e Monitoramento + +### O Que Registrar + +✅ **Seguro:** +- Erros de validação (estrutura, não valores) +- Falhas de autenticação (IP, timestamp) +- Operações bem-sucedidas (quem, quando, que recurso) + +❌ **Nunca Registre:** +- IBANs, números de contas, cartões +- Valores de transacções sensíveis +- Senhas, tokens de API, chaves criptográficas + +### Exemplo Seguro + +```csharp +_logger.LogWarning("Falha ao processar extracto para banco {Banco} (tipo de ficheiro: {Tipo})", + banco, tipo); + +// NÃO: +_logger.LogWarning("Falha ao processar extracto: {Extracto}", extractoJson); +``` + +## Auditoria + +Implemente logs de auditoria para conformidade: + +```csharp +public class LogAuditoria +{ + public int Id { get; set; } + public string Utilizador { get; set; } + public string Acao { get; set; } // "Processou extracto", "Gerou pagamento" + public string Recurso { get; set; } // ID do extracto, não dados sensíveis + public DateTime Timestamp { get; set; } + public string EnderecoIP { get; set; } + public string Resultado { get; set; } // "Sucesso", "Falha" +} +``` + +## Conformidade + +### Protecção de Dados Pessoais + +Se o seu sistema processa dados pessoais (ex: NUIT, nomes), cumpra: + +- **LEI MOÇAMBICANA DE PROTEÇÃO DE DADOS** (se aplicável) +- **RGPD** (se utilizadores da EU) +- **PCI DSS** (se processar dados de cartão) + +### Conformidade Bancária + +Em Moçambique, bancos estão sujeitos a: + +- **Normas BdM** (Banco de Moçambique) +- **Lei de Segurança Informática** +- **Controlos internos e auditoria** + +Consulte a legislação local antes de implementar em produção. + +## Atualizações de Segurança + +Subscreva notificações de segurança: + +1. **GitHub:** [Watch Releases](https://github.com/SimansoftMZ/BridgeBank/releases) — selecione "Releases only" +2. **NuGet:** Alertas automáticos para pacotes desatualizados +3. **Email:** (Quando disponível) Inscreva-se na mailing list de segurança + +## Contacto de Segurança + +Para questões de segurança confidenciais, entre em contacto com: + +- **Email:** [segurança do projecto] +- **GitHub Security Advisory:** [Reportar via GitHub](https://github.com/SimansoftMZ/BridgeBank/security/advisories) + +## Histórico de Versões de Segurança + +| Versão | Assunto | Data | +|--------|---------|------| +| 1.0.0+ | Versão inicial | [data] | + +*(Atualizaremos conforme novas versões forem lançadas)* + +## Referências + +- [OWASP Top 10](https://owasp.org/Top10/) +- [Microsoft .NET Security Best Practices](https://docs.microsoft.com/en-us/dotnet/fundamentals/security/) +- [PCI DSS Compliance Guide](https://www.pcisecuritystandards.org/) +- [Banco de Moçambique - Normas de Segurança](https://www.bancomocambique.mz/) + +--- + +**Última atualização:** 2026-04-16 +**Versão:** 1.0 From 23a62b322cb93f35bb8700a301c2ea217b04622c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 07:07:31 +0000 Subject: [PATCH 3/8] =?UTF-8?q?Aplicar=20feedback=20de=20review=20em=20seg?= =?UTF-8?q?uran=C3=A7a=20e=20dependabot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/SimansoftMZ/BridgeBank/sessions/95fa79cc-c17a-4a95-8ba2-ba7301146ab8 Co-authored-by: albertomandlate <14326204+albertomandlate@users.noreply.github.com> --- .github/dependabot.yml | 28 ++++++++++++--- CLAUDE.md | 78 ------------------------------------------ SECURITY.md | 23 ++++--------- 3 files changed, 30 insertions(+), 99 deletions(-) delete mode 100644 CLAUDE.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9e5914b..d8a2d94 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -13,10 +13,9 @@ updates: timezone: "Africa/Maputo" # Agrupar atualizações para reduzir número de PRs groups: - dependency-type: + dependencias-nuget: patterns: - - "dependency-type:production" - - "dependency-type:development" + - "*" open-pull-requests-limit: 10 pull-request-branch-name: separator: "/" @@ -25,7 +24,7 @@ updates: labels: - "dependencies" - "chore" - # Auto-merge para patches e minor versions + # Permitir apenas actualizações de dependências de desenvolvimento e indirectas allow: - dependency-type: "development" - dependency-type: "indirect" @@ -59,6 +58,27 @@ updates: prefix: "chore(docker):" include: "scope" + # Monitorar imagem base da API + - package-ecosystem: "docker" + directory: "/src/BridgeBank.Api" + schedule: + interval: "weekly" + day: "monday" + time: "04:00" + timezone: "Africa/Maputo" + open-pull-requests-limit: 5 + pull-request-branch-name: + separator: "/" + reviewers: + - "SimansoftMZ/maintainers" + labels: + - "dependencies" + - "docker" + - "chore" + commit-message: + prefix: "chore(docker):" + include: "scope" + # Monitorar GitHub Actions - package-ecosystem: "github-actions" directory: "/" diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index ec15fce..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,78 +0,0 @@ -# CLAUDE.md - -Este ficheiro fornece orientação ao Claude Code (claude.ai/code) quando trabalha com o código neste repositório. - -## Sobre o Projecto - -Toolkit .NET 10 open-source para reconciliação bancária em sistemas ERP moçambicanos. Publicado como pacotes NuGet (`Simansoft.BridgeBank.*`) e imagem Docker. Expõe também uma API REST com SDKs gerados para Python, TypeScript e Java. - -## Comandos - -```bash -# Compilar -dotnet build - -# Testes -dotnet test -dotnet test tests/BridgeBank.Core.Tests # projecto específico -dotnet test --collect:"XPlat Code Coverage" # com cobertura - -# Executar a API -dotnet run --project src/BridgeBank.Api -# http://localhost:8080 — API -# http://localhost:8080/scalar/v1 — documentação interactiva -# http://localhost:8080/openapi/v1.json — especificação OpenAPI - -# Docker -docker compose up --build - -# Regenerar SDKs (após alterar a API) -pwsh scripts/generate-sdks.ps1 # Windows -./scripts/generate-sdks.sh # Linux/macOS -``` - -## Arquitectura - -``` -src/ -├── BridgeBank.Core/ # Motor de reconciliação, classificador, modelos de domínio -├── BridgeBank.Parsers/ # Leitores de extractos bancários (Excel via NPOI) -├── BridgeBank.Generators/ # Geradores de ficheiros de pagamento (TXT, CSV, XML) -├── BridgeBank.ML/ # Classificação e reconciliação com ML.NET -└── BridgeBank.Api/ # Minimal API ASP.NET Core (Scalar + OpenAPI) -sdks/ # Clientes tipados gerados por Kiota (Python, TypeScript, Java) -openapi/ # Especificação OpenAPI gerada automaticamente no build -``` - -- **`BridgeBank.Core`** — Núcleo sem dependências externas, compatível com AOT. Contém `MotorReconciliacao`, `ClassificadorTransacao` e as interfaces de extensibilidade. -- **`BridgeBank.Parsers`** — Cada banco tem a sua implementação em `Bancos/`, estendendo `LeitorExcelBase`. -- **`BridgeBank.Generators`** — Cada banco tem a sua implementação em `Bancos/`, implementando `IGeradorFicheiroPagamento`. -- **`BridgeBank.ML`** — Liga-se ao Core via `IRegraClassificacao`. Pode treinar com dados sintéticos. -- **`BridgeBank.Api`** — Gera a especificação OpenAPI em `openapi/` durante o build. Os SDKs são gerados a partir daí. - -### Pontos de Extensibilidade -- Nova estratégia de correspondência → implementar `IEstrategiaCorrespondencia` -- Nova regra de classificação → implementar `IRegraClassificacao` -- Novo banco (leitor) → estender `LeitorExcelBase` e implementar `ILeitorExtrato` -- Novo banco (gerador) → implementar `IGeradorFicheiroPagamento` - -## Convenções de Código - -- **Classes e métodos**: PascalCase em **português** (ex: `MotorReconciliacao`, `ReconciliarTransacoes`) -- **Variáveis locais**: camelCase em **português** (ex: `transacaoBancaria`) -- **Projectos e namespaces**: PascalCase em **inglês** (ex: `Simansoft.BridgeBank.Core`) -- Nullable reference types e `ImplicitUsings` activos - -## Estratégia de Branches - -GitHub Flow — todo o trabalho entra em `main` via Pull Request: - -``` -main (protegido) - ├── feature/* - ├── fix/* - ├── docs/* - └── chore/* -``` - -Tags `v*.*.*` em `main` disparam publicação automática no NuGet e Docker Hub. diff --git a/SECURITY.md b/SECURITY.md index 0a666f0..ea73822 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,21 +12,11 @@ Se descobrir uma vulnerabilidade de segurança, **não abra uma issue pública n 2. Clique em **"Report a vulnerability"** 3. Descreva a vulnerabilidade com detalhes técnicos -### Via Email (Segurança) - -Envie um email para a equipa de segurança do projecto com: - -- Descrição clara da vulnerabilidade -- Passos para reproduzir -- Impacto potencial -- Versões afectadas -- Sugestões de correcção (se possível) - **A segurança é uma prioridade — as vulnerabilidades reportadas serão tratadas com urgência.** ## Processo de Divulgação -1. **Recepção:** Acknowledgeamos a recepção do relatório dentro de 48 horas +1. **Recepção:** Confirmamos a recepção do relatório dentro de 48 horas 2. **Avaliação:** A equipa avalia a vulnerabilidade e o seu impacto 3. **Correcção:** Desenvolvemos uma correcção em segredo numa branch privada 4. **Teste:** A correcção é validada e testada completamente @@ -64,7 +54,7 @@ Se contribuir para o projecto: - **Não envie segredos** — Revise seus commits antes de push; evite expor chaves, tokens ou dados sensíveis - **Testes de segurança** — Teste casos extremos e entrada malformada -- **Dependências** — Use versões knowns de bibliotecas; revise `csproj` para dependências desatualizadas +- **Dependências** — Use versões conhecidas de bibliotecas; revise `csproj` para dependências desatualizadas - **Code review** — Aceite feedback crítico sobre segurança ## Responsabilidades de Segurança do Projecto @@ -273,7 +263,7 @@ public class LogAuditoria Se o seu sistema processa dados pessoais (ex: NUIT, nomes), cumpra: - **LEI MOÇAMBICANA DE PROTEÇÃO DE DADOS** (se aplicável) -- **RGPD** (se utilizadores da EU) +- **RGPD** (se utilizadores da UE) - **PCI DSS** (se processar dados de cartão) ### Conformidade Bancária @@ -292,20 +282,19 @@ Subscreva notificações de segurança: 1. **GitHub:** [Watch Releases](https://github.com/SimansoftMZ/BridgeBank/releases) — selecione "Releases only" 2. **NuGet:** Alertas automáticos para pacotes desatualizados -3. **Email:** (Quando disponível) Inscreva-se na mailing list de segurança +3. **GitHub Security Advisory:** Subscreva actualizações de advisories de segurança do repositório ## Contacto de Segurança -Para questões de segurança confidenciais, entre em contacto com: +Para questões de segurança confidenciais, utilize: -- **Email:** [segurança do projecto] - **GitHub Security Advisory:** [Reportar via GitHub](https://github.com/SimansoftMZ/BridgeBank/security/advisories) ## Histórico de Versões de Segurança | Versão | Assunto | Data | |--------|---------|------| -| 1.0.0+ | Versão inicial | [data] | +| 1.0.0+ | Versão inicial | 2026-04-16 | *(Atualizaremos conforme novas versões forem lançadas)* From 6528a00b5c0c7c97e89fcccdb530813351fc1919 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 07:40:45 +0000 Subject: [PATCH 4/8] =?UTF-8?q?Aplicar=20segundo=20feedback=20de=20revis?= =?UTF-8?q?=C3=A3o=20em=20SECURITY=20e=20Dependabot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/SimansoftMZ/BridgeBank/sessions/88e06d28-a00e-4ae8-afa0-7444346d2df5 Co-authored-by: albertomandlate <14326204+albertomandlate@users.noreply.github.com> --- .github/dependabot.yml | 25 ----------------- SECURITY.md | 64 +++++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d8a2d94..75ad49d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,10 +24,6 @@ updates: labels: - "dependencies" - "chore" - # Permitir apenas actualizações de dependências de desenvolvimento e indirectas - allow: - - dependency-type: "development" - - dependency-type: "indirect" # Ignorar versões pré-lançamento ignore: - dependency-name: "*" @@ -37,27 +33,6 @@ updates: prefix: "chore(deps):" include: "scope" - # Monitorar dependências Docker - - package-ecosystem: "docker" - directory: "/" - schedule: - interval: "weekly" - day: "monday" - time: "04:00" - timezone: "Africa/Maputo" - open-pull-requests-limit: 5 - pull-request-branch-name: - separator: "/" - reviewers: - - "SimansoftMZ/maintainers" - labels: - - "dependencies" - - "docker" - - "chore" - commit-message: - prefix: "chore(docker):" - include: "scope" - # Monitorar imagem base da API - package-ecosystem: "docker" directory: "/src/BridgeBank.Api" diff --git a/SECURITY.md b/SECURITY.md index ea73822..f9a3dc8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -78,7 +78,7 @@ Não há vulnerabilidades conhecidas no momento da última atualização. Consul - **Armazenamento** — Criptografe ficheiros de extracto em repouso (ex: AES-256) - **Transmissão** — Use HTTPS/TLS ao enviar extractos para a API - **Logs** — Não registre IBANs, números de contas ou valores sensíveis em logs -- **Temporário** — Delete ficheiros extracto após processamento +- **Temporário** — Delete ficheiros de extracto após processamento ### Números de Contas Bancárias @@ -125,10 +125,28 @@ var allowedTypes = new[] { "application/vnd.ms-excel", if (!allowedTypes.Contains(file.ContentType)) throw new InvalidOperationException("Tipo de ficheiro não permitido"); -// Validar conteúdo -var extrato = leitor.LerExtrato(file.FileName); -if (extrato?.Transacoes == null || !extrato.Transacoes.Any()) - throw new InvalidOperationException("Extracto vazio ou inválido"); +// Validar conteúdo (guarde o upload num ficheiro temporário antes de processar) +var extensaoOriginal = Path.GetExtension(file.FileName); +var caminhoTemporario = Path.ChangeExtension( + Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), + extensaoOriginal); + +try +{ + await using (var stream = new FileStream(caminhoTemporario, FileMode.Create)) + { + await file.CopyToAsync(stream); + } + + var extrato = leitor.LerExtrato(caminhoTemporario); + if (extrato?.Transacoes == null || !extrato.Transacoes.Any()) + throw new InvalidOperationException("Extracto vazio ou inválido"); +} +finally +{ + if (File.Exists(caminhoTemporario)) + File.Delete(caminhoTemporario); +} ``` ## Gestão de Dependências @@ -164,7 +182,10 @@ Se utilizar a API REST, configure HTTPS obrigatório: ```csharp // Program.cs -app.UseHsts(); // HTTP Strict-Transport-Security +if (!app.Environment.IsDevelopment()) +{ + app.UseHsts(); // HTTP Strict-Transport-Security +} app.UseHttpsRedirection(); // Certificado SSL (produção) @@ -196,25 +217,28 @@ using System.Text; public class CriptografiaDados { - public static string Encriptar(string dados, byte[] chave) + public static byte[] EncriptarAutenticado(string dados, byte[] chave) { - using var aes = Aes.Create(); - aes.Key = chave; - aes.GenerateIV(); - - using var encryptor = aes.CreateEncryptor(); - using var ms = new MemoryStream(); - ms.Write(aes.IV, 0, aes.IV.Length); - using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) - { - cs.Write(Encoding.UTF8.GetBytes(dados)); - } - - return Convert.ToBase64String(ms.ToArray()); + var nonce = RandomNumberGenerator.GetBytes(12); // 96 bits para GCM + var textoPlano = Encoding.UTF8.GetBytes(dados); + var textoCifrado = new byte[textoPlano.Length]; + var tag = new byte[16]; + + using var aes = new AesGcm(chave, tagSizeInBytes: 16); + aes.Encrypt(nonce, textoPlano, textoCifrado, tag); + + var resultado = new byte[nonce.Length + tag.Length + textoCifrado.Length]; + Buffer.BlockCopy(nonce, 0, resultado, 0, nonce.Length); + Buffer.BlockCopy(tag, 0, resultado, nonce.Length, tag.Length); + Buffer.BlockCopy(textoCifrado, 0, resultado, nonce.Length + tag.Length, textoCifrado.Length); + + return resultado; } } ``` +**Nota:** Guarde e rote chaves criptográficas num cofre seguro (ex: Azure Key Vault, AWS KMS ou DPAPI), em vez de embutir chaves no código ou ficheiros de configuração. + ## Logs e Monitoramento ### O Que Registrar From 48fa25e1605162979a45ba77e8d262fb1b6f3a52 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 07:42:40 +0000 Subject: [PATCH 5/8] =?UTF-8?q?Refor=C3=A7ar=20exemplos=20de=20seguran?= =?UTF-8?q?=C3=A7a=20no=20SECURITY.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/SimansoftMZ/BridgeBank/sessions/88e06d28-a00e-4ae8-afa0-7444346d2df5 Co-authored-by: albertomandlate <14326204+albertomandlate@users.noreply.github.com> --- SECURITY.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index f9a3dc8..2b0f97f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -126,10 +126,14 @@ if (!allowedTypes.Contains(file.ContentType)) throw new InvalidOperationException("Tipo de ficheiro não permitido"); // Validar conteúdo (guarde o upload num ficheiro temporário antes de processar) +var caminhoTemporario = Path.GetTempFileName(); var extensaoOriginal = Path.GetExtension(file.FileName); -var caminhoTemporario = Path.ChangeExtension( - Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), - extensaoOriginal); +if (!string.IsNullOrWhiteSpace(extensaoOriginal)) +{ + var caminhoComExtensao = Path.ChangeExtension(caminhoTemporario, extensaoOriginal); + File.Move(caminhoTemporario, caminhoComExtensao, overwrite: true); + caminhoTemporario = caminhoComExtensao; +} try { @@ -217,8 +221,17 @@ using System.Text; public class CriptografiaDados { + /// + /// Encripta dados com AES-GCM e devolve nonce (12 bytes) + tag (16 bytes) + texto cifrado. + /// + /// Texto em claro a encriptar. + /// Chave AES de 16, 24 ou 32 bytes. + /// Buffer concatenado no formato nonce + tag + texto cifrado. public static byte[] EncriptarAutenticado(string dados, byte[] chave) { + if (chave is null || (chave.Length != 16 && chave.Length != 24 && chave.Length != 32)) + throw new ArgumentException("A chave deve ter 16, 24 ou 32 bytes.", nameof(chave)); + var nonce = RandomNumberGenerator.GetBytes(12); // 96 bits para GCM var textoPlano = Encoding.UTF8.GetBytes(dados); var textoCifrado = new byte[textoPlano.Length]; @@ -237,7 +250,7 @@ public class CriptografiaDados } ``` -**Nota:** Guarde e rote chaves criptográficas num cofre seguro (ex: Azure Key Vault, AWS KMS ou DPAPI), em vez de embutir chaves no código ou ficheiros de configuração. +**Nota:** Guarde e rote chaves criptográficas num cofre seguro (ex: Azure Key Vault, AWS KMS ou DPAPI), em vez de embutir chaves no código ou ficheiros de configuração. O nonce deve ser **único por chave**; em cenários de alto volume, prefira um esquema monotónico (contador) por chave para prevenir reutilização. ## Logs e Monitoramento From 27f69fc042b4a3a2cf40a5bc79811c6f89da0ae9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 07:43:58 +0000 Subject: [PATCH 6/8] =?UTF-8?q?Endurecer=20exemplos=20de=20seguran=C3=A7a?= =?UTF-8?q?=20com=20valida=C3=A7=C3=B5es=20adicionais?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/SimansoftMZ/BridgeBank/sessions/88e06d28-a00e-4ae8-afa0-7444346d2df5 Co-authored-by: albertomandlate <14326204+albertomandlate@users.noreply.github.com> --- SECURITY.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 2b0f97f..cf242b9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -128,6 +128,14 @@ if (!allowedTypes.Contains(file.ContentType)) // Validar conteúdo (guarde o upload num ficheiro temporário antes de processar) var caminhoTemporario = Path.GetTempFileName(); var extensaoOriginal = Path.GetExtension(file.FileName); +var extensoesPermitidas = new HashSet(StringComparer.OrdinalIgnoreCase) +{ + ".xlsx", ".xls", ".json" +}; + +if (string.IsNullOrWhiteSpace(extensaoOriginal) || !extensoesPermitidas.Contains(extensaoOriginal)) + throw new InvalidOperationException("Extensão de ficheiro não permitida"); + if (!string.IsNullOrWhiteSpace(extensaoOriginal)) { var caminhoComExtensao = Path.ChangeExtension(caminhoTemporario, extensaoOriginal); @@ -236,9 +244,10 @@ public class CriptografiaDados var textoPlano = Encoding.UTF8.GetBytes(dados); var textoCifrado = new byte[textoPlano.Length]; var tag = new byte[16]; + var dadosAssociados = Encoding.UTF8.GetBytes("contexto:bridgebank"); // AAD opcional using var aes = new AesGcm(chave, tagSizeInBytes: 16); - aes.Encrypt(nonce, textoPlano, textoCifrado, tag); + aes.Encrypt(nonce, textoPlano, textoCifrado, tag, dadosAssociados); var resultado = new byte[nonce.Length + tag.Length + textoCifrado.Length]; Buffer.BlockCopy(nonce, 0, resultado, 0, nonce.Length); @@ -250,7 +259,7 @@ public class CriptografiaDados } ``` -**Nota:** Guarde e rote chaves criptográficas num cofre seguro (ex: Azure Key Vault, AWS KMS ou DPAPI), em vez de embutir chaves no código ou ficheiros de configuração. O nonce deve ser **único por chave**; em cenários de alto volume, prefira um esquema monotónico (contador) por chave para prevenir reutilização. +**Nota:** Guarde e rote chaves criptográficas num cofre seguro (ex: Azure Key Vault, AWS KMS ou DPAPI), em vez de embutir chaves no código ou ficheiros de configuração. O nonce deve ser **único por chave**; em cenários de alto volume, prefira um esquema monotónico (contador) por chave para prevenir reutilização. Se usar AAD, preserve e forneça exactamente o mesmo valor durante a desencriptação. ## Logs e Monitoramento From 0ab2b8c219fafcedaeb15f4463a5a9d6f0369a51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 07:45:41 +0000 Subject: [PATCH 7/8] =?UTF-8?q?Ajustar=20snippets=20de=20seguran=C3=A7a=20?= =?UTF-8?q?conforme=20valida=C3=A7=C3=A3o=20final?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/SimansoftMZ/BridgeBank/sessions/88e06d28-a00e-4ae8-afa0-7444346d2df5 Co-authored-by: albertomandlate <14326204+albertomandlate@users.noreply.github.com> --- .github/dependabot.yml | 2 +- SECURITY.md | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 75ad49d..b462b19 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -28,7 +28,7 @@ updates: ignore: - dependency-name: "*" versions: ["*-*"] - # Ativar commit signing se configurado + # Em NuGet, include: scope adiciona o nome da dependência no commit message commit-message: prefix: "chore(deps):" include: "scope" diff --git a/SECURITY.md b/SECURITY.md index cf242b9..4fea2a9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -136,12 +136,9 @@ var extensoesPermitidas = new HashSet(StringComparer.OrdinalIgnoreCase) if (string.IsNullOrWhiteSpace(extensaoOriginal) || !extensoesPermitidas.Contains(extensaoOriginal)) throw new InvalidOperationException("Extensão de ficheiro não permitida"); -if (!string.IsNullOrWhiteSpace(extensaoOriginal)) -{ - var caminhoComExtensao = Path.ChangeExtension(caminhoTemporario, extensaoOriginal); - File.Move(caminhoTemporario, caminhoComExtensao, overwrite: true); - caminhoTemporario = caminhoComExtensao; -} +var caminhoComExtensao = Path.ChangeExtension(caminhoTemporario, extensaoOriginal); +File.Move(caminhoTemporario, caminhoComExtensao, overwrite: true); +caminhoTemporario = caminhoComExtensao; try { @@ -234,8 +231,9 @@ public class CriptografiaDados /// /// Texto em claro a encriptar. /// Chave AES de 16, 24 ou 32 bytes. + /// AAD opcional; deve ser exactamente o mesmo na desencriptação. /// Buffer concatenado no formato nonce + tag + texto cifrado. - public static byte[] EncriptarAutenticado(string dados, byte[] chave) + public static byte[] EncriptarAutenticado(string dados, byte[] chave, byte[]? dadosAssociados = null) { if (chave is null || (chave.Length != 16 && chave.Length != 24 && chave.Length != 32)) throw new ArgumentException("A chave deve ter 16, 24 ou 32 bytes.", nameof(chave)); @@ -244,7 +242,6 @@ public class CriptografiaDados var textoPlano = Encoding.UTF8.GetBytes(dados); var textoCifrado = new byte[textoPlano.Length]; var tag = new byte[16]; - var dadosAssociados = Encoding.UTF8.GetBytes("contexto:bridgebank"); // AAD opcional using var aes = new AesGcm(chave, tagSizeInBytes: 16); aes.Encrypt(nonce, textoPlano, textoCifrado, tag, dadosAssociados); From fe2e83c8b70b31438c1cf97970d1abc2d763bfe4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 07:46:47 +0000 Subject: [PATCH 8/8] =?UTF-8?q?Corrigir=20snippet=20de=20ficheiro=20tempor?= =?UTF-8?q?=C3=A1rio=20e=20nota=20de=20compatibilidade?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/SimansoftMZ/BridgeBank/sessions/88e06d28-a00e-4ae8-afa0-7444346d2df5 Co-authored-by: albertomandlate <14326204+albertomandlate@users.noreply.github.com> --- SECURITY.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 4fea2a9..ab95e6b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -126,7 +126,6 @@ if (!allowedTypes.Contains(file.ContentType)) throw new InvalidOperationException("Tipo de ficheiro não permitido"); // Validar conteúdo (guarde o upload num ficheiro temporário antes de processar) -var caminhoTemporario = Path.GetTempFileName(); var extensaoOriginal = Path.GetExtension(file.FileName); var extensoesPermitidas = new HashSet(StringComparer.OrdinalIgnoreCase) { @@ -136,9 +135,7 @@ var extensoesPermitidas = new HashSet(StringComparer.OrdinalIgnoreCase) if (string.IsNullOrWhiteSpace(extensaoOriginal) || !extensoesPermitidas.Contains(extensaoOriginal)) throw new InvalidOperationException("Extensão de ficheiro não permitida"); -var caminhoComExtensao = Path.ChangeExtension(caminhoTemporario, extensaoOriginal); -File.Move(caminhoTemporario, caminhoComExtensao, overwrite: true); -caminhoTemporario = caminhoComExtensao; +var caminhoTemporario = Path.GetTempFileName(); try { @@ -256,7 +253,7 @@ public class CriptografiaDados } ``` -**Nota:** Guarde e rote chaves criptográficas num cofre seguro (ex: Azure Key Vault, AWS KMS ou DPAPI), em vez de embutir chaves no código ou ficheiros de configuração. O nonce deve ser **único por chave**; em cenários de alto volume, prefira um esquema monotónico (contador) por chave para prevenir reutilização. Se usar AAD, preserve e forneça exactamente o mesmo valor durante a desencriptação. +**Nota:** Guarde e rote chaves criptográficas num cofre seguro (ex: Azure Key Vault, AWS KMS ou DPAPI), em vez de embutir chaves no código ou ficheiros de configuração. O nonce deve ser **único por chave**; em cenários de alto volume, prefira um esquema monotónico (contador) por chave para prevenir reutilização. Se usar AAD, preserve e forneça exactamente o mesmo valor durante a desencriptação. `AesGcm` requer .NET 6.0 ou superior. ## Logs e Monitoramento