Skip to content
Draft
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
2f99e22
feat: Add project and launch settings
MH321Productions Aug 18, 2025
6dee93a
feat: Add extensions for the console and static file paths
MH321Productions Aug 18, 2025
1eae560
feat: Add the two commands and the main program
MH321Productions Aug 18, 2025
b2b5ec8
Merge branch 'main' into identity-deletion-verifier
MH321Productions Aug 18, 2025
0aeba1b
feat: Prepare github workflow
MH321Productions Aug 19, 2025
fd48095
ci: Finish workflow
MH321Productions Aug 20, 2025
bc74073
fix: Change ports of baseUrls
MH321Productions Aug 20, 2025
d00bc69
fix: Create temp export directory if it doesn't exist
MH321Productions Aug 20, 2025
93020f9
chore: Add failure archive of docker logs
MH321Productions Aug 20, 2025
65592cc
ci: upload exported db file and identity file (not only on failure fo…
MH321Productions Aug 20, 2025
0087b7a
fix: Fix variables
MH321Productions Aug 20, 2025
f9692c9
chore: Only upload exported db files on failure
MH321Productions Aug 20, 2025
4d15bbc
Merge branch 'main' into identity-deletion-verifier
MH321Productions Aug 21, 2025
e3f2021
fix: Delete token allocations instead of anonymizing them when deleti…
MH321Productions Aug 22, 2025
a7f481f
chore: Add multi-run config for the identity deletion verifier workflow
MH321Productions Aug 22, 2025
63d9e25
feat: Add datawallets
MH321Productions Aug 22, 2025
c42fbec
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 23, 2025
186ed54
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 24, 2025
ce4c321
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 24, 2025
cd35c90
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 25, 2025
1e6e749
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 25, 2025
68c783b
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 26, 2025
2f1a772
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 26, 2025
395ccbf
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 26, 2025
920183a
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 26, 2025
7b4250a
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 27, 2025
8637877
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 27, 2025
23e5f0d
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 27, 2025
18c22df
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 28, 2025
9f2e612
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Aug 31, 2025
634a201
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 1, 2025
94b3d97
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 1, 2025
ca37a82
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 1, 2025
b0ffc1c
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 1, 2025
2b2fb4d
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 1, 2025
aac6368
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 1, 2025
e329e5f
chore: Remove old IdentityDeletionVerifier project
MH321Productions Sep 9, 2025
fc34241
fix: Fix syntax and output file of SqlServer dump script
MH321Productions Sep 9, 2025
8ba8f49
chore: Import PgDump and SMO
MH321Productions Sep 9, 2025
79e98d6
feat: Add database exporters
MH321Productions Sep 9, 2025
5c73924
feat: Add Sql extractors
MH321Productions Sep 9, 2025
bceecc3
feat: Add deletion verifiers
MH321Productions Sep 9, 2025
1148aa1
chore: Add database configuration to identity deletion job configuration
MH321Productions Sep 9, 2025
6936ef3
feat: Verify deletion after finishing
MH321Productions Sep 9, 2025
631361c
chore: Add helper method to deconstruct connection string
MH321Productions Sep 9, 2025
c5ad7aa
feat: Register deletion verifier, db exporter and sql extractor for d…
MH321Productions Sep 9, 2025
d7caf17
test: Add tests for the deletion verifier and the worker when the ver…
MH321Productions Sep 9, 2025
ae149c8
chore: Remove old deletion verifier workflow
MH321Productions Sep 9, 2025
ed09310
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 9, 2025
d1300d0
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 9, 2025
e5777b7
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 9, 2025
556b4b9
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 10, 2025
382e581
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 10, 2025
dbaa330
chore: Remove unneccessary file check
MH321Productions Sep 10, 2025
37a2cea
chore: Install pg_dump in docker image
MH321Productions Sep 10, 2025
df5e405
fix: Typo in Postgres connection string
MH321Productions Sep 10, 2025
ede5825
chore: Change pg_dump version in docker image
MH321Productions Sep 10, 2025
9884e96
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 10, 2025
dfed17f
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 10, 2025
0105ea2
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 11, 2025
50f2f6f
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 11, 2025
777a41f
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 11, 2025
aa3ee48
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 11, 2025
8271e56
fix: Make User ID uppercase in postgres appsettings override json
MH321Productions Sep 11, 2025
4fa3017
Merge remote-tracking branch 'origin/identity-deletion-verifier' into…
MH321Productions Sep 11, 2025
9fd59bc
test: Update apk package list before installing
MH321Productions Sep 12, 2025
6985b86
test: Log pg_dump version after installing
MH321Productions Sep 12, 2025
6ec6c26
test: Log pg dump version on program startup
MH321Productions Sep 12, 2025
49d2efc
test: Log pg dump version at the start of the worker
MH321Productions Sep 12, 2025
a73d51e
test: Log pg dump version in integration test
MH321Productions Sep 12, 2025
2f7108a
test: Log pg dump path
MH321Productions Sep 12, 2025
2918783
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 12, 2025
9a3fd87
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 13, 2025
c7c69b9
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 15, 2025
ee2042f
ci: Install Postgres 17 in pipeline
MH321Productions Sep 15, 2025
01d7db7
Merge remote-tracking branch 'origin/identity-deletion-verifier' into…
MH321Productions Sep 15, 2025
312ed0e
chore: Change Postgres User ID
MH321Productions Sep 15, 2025
4b95189
fix: Change User ID in local postgres appsettings override file
MH321Productions Sep 16, 2025
c6a1e39
chore: Clean up unneccessary debug messages
MH321Productions Sep 16, 2025
2d4c314
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 17, 2025
8101f04
test: Include passed integration tests in summary
MH321Productions Sep 17, 2025
1f79cf2
Merge remote-tracking branch 'origin/identity-deletion-verifier' into…
MH321Productions Sep 17, 2025
412b0c9
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 17, 2025
e5096b2
test: Set a timeout of 30 seconds per test to identify the faulty one
MH321Productions Sep 17, 2025
5e44cbb
Merge remote-tracking branch 'origin/identity-deletion-verifier' into…
MH321Productions Sep 17, 2025
e76f56f
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 18, 2025
ca21c4c
test: Log every single step
MH321Productions Sep 18, 2025
cfaa695
test: Capture everything
MH321Productions Sep 18, 2025
ea7eec0
test: Remove one capture to trigger new run
MH321Productions Sep 19, 2025
22da433
test: Don't verify
MH321Productions Sep 19, 2025
f362ec7
test: Re-add verification
MH321Productions Sep 19, 2025
7af156e
test: Write a separate verification test and comment out the faulty one
MH321Productions Sep 19, 2025
f8bf433
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 20, 2025
cfaa71d
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 20, 2025
0e9174a
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 22, 2025
19ee5e2
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 22, 2025
e99e730
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 22, 2025
6adac25
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 22, 2025
7173e09
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 22, 2025
10c90e4
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 23, 2025
32112c8
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 23, 2025
50a1749
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 23, 2025
5e6bc84
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 23, 2025
5d67d6b
chore: Re-add faulty test, increase timeout to 60s
MH321Productions Sep 23, 2025
dceabe2
test: Log time in every test
MH321Productions Sep 24, 2025
0fe748c
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 29, 2025
b2f63b3
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 29, 2025
53f1768
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Sep 29, 2025
f51a89f
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Oct 2, 2025
1489355
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Oct 6, 2025
3c8f8fc
Merge branch 'main' into identity-deletion-verifier
mergify[bot] Oct 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 98 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ jobs:
strategy:
fail-fast: false
matrix:
database: [sqlserver, postgres]
database: [ sqlserver, postgres ]
test-project:
- display-name: admin-api
path: Applications/AdminApi/test/AdminApi.Tests.Integration
Expand Down Expand Up @@ -255,7 +255,7 @@ jobs:
strategy:
fail-fast: false
matrix:
database: [sqlserver, postgres]
database: [ sqlserver, postgres ]
needs: image-test-builds
steps:
- name: Checkout backbone repository
Expand Down Expand Up @@ -357,3 +357,99 @@ jobs:
run: dotnet restore /p:ContinuousIntegrationBuild=true ./Backbone.sln
- name: Validate Licenses
run: nuget-license --input ./Backbone.sln --allowed-license-types ./.ci/allowedLicenses.json --ignored-packages ./.ci/ignoredPackages.json --output table --error-only

verify-identity-deletion:
name: Validate Identity deletion (on ${{matrix.database.type}})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
database:
- type: postgres
env:
Database__Provider: Postgres
Database__ConnectionString: "Server=postgres;Database=enmeshed;User Id=devices;Password=Passw0rd;Port=5432"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please stay with the typical config hierarchy, so that

  1. It's consistent
  2. I don't have to provide a separate config during deployment

In this case, this means:

Suggested change
Database__Provider: Postgres
Database__ConnectionString: "Server=postgres;Database=enmeshed;User Id=devices;Password=Passw0rd;Port=5432"
Infrastructure__SqlDatabase__Provider: Postgres
Infrastructure__SqlDatabase__ConnectionString: "Server=postgres;Database=enmeshed;User Id=devices;Password=Passw0rd;Port=5432"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't you use the already existing appsettings.override..docker.json files instead of specifying the config via env vars? See the integration-test job in the same file for guidance

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused. Why does this work even though you the docker internal hostname postgres? It shouldn't be available locally

- type: sqlserver
env:
Database__Provider: SqlServer
Database__ConnectionString: "Server=sqlserver;Database=enmeshed;User Id=devices;Password=Passw0rd;TrustServerCertificate=True"
needs: image-test-builds
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Setup Dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.x

- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: ${{ runner.os }}-nuget-

- name: Download cached Docker images
uses: actions/download-artifact@v5
with:
path: /tmp
pattern: docker-*
merge-multiple: true

- name: Load Docker images and build applications
run: |
{
./.ci/loadDockerImages.sh
} &
{
# The following two lines are for the identity deletion job only
mv appsettings.override.json appsettings.override.json.bak
cp .ci/appsettings.override.${{matrix.database.type}}.local.json appsettings.override.json

dotnet restore ./Applications/IdentityDeletionVerifier/src/IdentityDeletionVerifier/IdentityDeletionVerifier.csproj
dotnet restore ./Applications/IdentityDeletionJobs/src/Job.IdentityDeletion/Job.IdentityDeletion.csproj
dotnet restore ./Applications/AdminCli/src/AdminCli/AdminCli.csproj

dotnet build --no-restore ./Applications/IdentityDeletionVerifier/src/IdentityDeletionVerifier/IdentityDeletionVerifier.csproj
dotnet build --no-restore ./Applications/IdentityDeletionJobs/src/Job.IdentityDeletion/Job.IdentityDeletion.csproj
dotnet build --no-restore ./Applications/AdminCli/src/AdminCli/AdminCli.csproj
}
wait

- name: Start compose stack
run: |
docker compose -f ./.ci/compose.test.yml -f ./.ci/compose.test.${{matrix.database.type}}.yml down -v
docker compose -f ./.ci/compose.test.yml -f ./.ci/compose.test.${{matrix.database.type}}.yml up --no-build --wait -d
docker compose -f ./.ci/compose.test.yml -f ./.ci/compose.test.${{matrix.database.type}}.yml wait admin-cli

- name: Create identities, relationships etc. and initiate deletion processes
run: dotnet run --no-build --no-restore --project ./Applications/IdentityDeletionVerifier/src/IdentityDeletionVerifier/IdentityDeletionVerifier.csproj init --consumerBaseUrl http://localhost:5000 --adminBaseUrl http://localhost:5173

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
run: dotnet run --no-build --no-restore --project ./Applications/IdentityDeletionVerifier/src/IdentityDeletionVerifier/IdentityDeletionVerifier.csproj init --consumerBaseUrl http://localhost:5000 --adminBaseUrl http://localhost:5173
run: dotnet run --no-build --no-restore --project ./Applications/IdentityDeletionVerifier/src/IdentityDeletionVerifier/IdentityDeletionVerifier.csproj init --consumerApiBaseUrl http://localhost:5000 --adminApiBaseUrl http://localhost:5173


- name: Run Identity deletion job
run: dotnet run --no-build --no-restore --project ./Applications/IdentityDeletionJobs/src/Job.IdentityDeletion/Job.IdentityDeletion.csproj --Worker ActualDeletionWorker

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should ideally run in Docker (with the production image), so that we are as close to the production scenario as possible


- name: Export databse via Admin Cli
run: dotnet run --no-build --no-restore --project ./Applications/AdminCli/src/AdminCli/AdminCli.csproj database export --sensitive
env: ${{matrix.database.env}}

- name: Check exported database file
run: dotnet run --no-build --no-restore --project ./Applications/IdentityDeletionVerifier/src/IdentityDeletionVerifier/IdentityDeletionVerifier.csproj check

- name: Save Docker Logs
if: failure()
run: docker compose -f ./.ci/compose.test.yml -f ./.ci/compose.test.${{matrix.database.type}}.yml logs > logs.txt

- name: Archive logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: identity-deletion-verifier-docker-${{matrix.database.type}}
path: logs.txt

- name: Archive exported database and identity files
if: failure()
uses: actions/upload-artifact@v4
with:
name: identity-deletion-verifier-exported-db-${{matrix.database.type}}
path: /tmp/enmeshed/backbone
55 changes: 55 additions & 0 deletions .run/Identity Deletion verifier.run.xml

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This configuration does everything at once? So:

  1. Init
  2. Deletion Job
  3. Verify
    ?

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Identity Deletion verifier" type="com.intellij.execution.configurations.multilaunch" factoryName="MultiLaunchConfiguration">
<rows>
<ExecutableRowSnapshot>
<option name="condition">
<ConditionSnapshot>
<option name="type" value="immediately" />
</ConditionSnapshot>
</option>
<option name="executable">
<ExecutableSnapshot>
<option name="id" value="runConfig:.NET Launch Settings Profile.IdentityDeletionVerifier: Init" />
</ExecutableSnapshot>
</option>
</ExecutableRowSnapshot>
<ExecutableRowSnapshot>
<option name="condition">
<ConditionSnapshot>
<option name="type" value="afterPreviousFinished" />
</ConditionSnapshot>
</option>
<option name="executable">
<ExecutableSnapshot>
<option name="id" value="runConfig:.NET Launch Settings Profile.Job.IdentityDeletion: Job.IdentityDeletion.ActualDeletion" />
</ExecutableSnapshot>
</option>
</ExecutableRowSnapshot>
<ExecutableRowSnapshot>
<option name="condition">
<ConditionSnapshot>
<option name="type" value="afterPreviousFinished" />
</ConditionSnapshot>
</option>
<option name="executable">
<ExecutableSnapshot>
<option name="id" value="runConfig:.NET Launch Settings Profile.AdminCli: Export database" />
</ExecutableSnapshot>
</option>
</ExecutableRowSnapshot>
<ExecutableRowSnapshot>
<option name="condition">
<ConditionSnapshot>
<option name="type" value="afterPreviousFinished" />
</ConditionSnapshot>
</option>
<option name="executable">
<ExecutableSnapshot>
<option name="id" value="runConfig:.NET Launch Settings Profile.IdentityDeletionVerifier: Check" />
</ExecutableSnapshot>
</option>
</ExecutableRowSnapshot>
</rows>
<method v="2" />
</configuration>
</component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System.CommandLine;
using System.IO.Compression;
using System.Text;
using Spectre.Console;

namespace Backbone.IdentityDeletionVerifier.Commands;

public class CheckCommand : Command
{
public CheckCommand() : base("check", "Check the exported database file for the given identity address in the temp directory")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project is called IdentityDeletionVerifier. Shouldn't this command then be called verify instead of check?

{
SetAction(Handle);
}

private async Task<int> Handle(ParseResult _, CancellationToken cancellationToken)
{
if (!DirectoryExists())
{
AnsiConsole.MarkupLineInterpolated($"[red bold]The temp directory[/][grey bold]{FilePaths.PATH_TO_TEMP_DIR} [/][red bold]doesn't exist.[/]");
return -1;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IdentitiesFileExists already checks implicitly for the existence of the directory


if (!IdentitiesFileExists())
{
AnsiConsole.MarkupLine("[red bold]The deleted identities file doesn't exist. Run the Init command first.[/]");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first part of the error message sounds incorrect if you read it without any special knowledge. Because OF COURSE the identities file doesn't exist if it was deleted. 😉

return -1;
}

if (!ExportFileExists())
{
AnsiConsole.MarkupLine("[red bold]No exported database file found. Run the Admin Cli Export Database command first.[/]");
return -1;
}

var a = await GetIdentityToCheck();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird name

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the name of the method either. How about DoesIdentityFileHaveContent?

if (a == null)
{
AnsiConsole.MarkupLineInterpolated($"[red bold]The identities file couldn't be read or has no Identity[/]");
return -1;
}

AnsiConsole.MarkupLineInterpolated($"[green bold]Identity to check:[/] [grey bold]{a}[/]");

return await CheckExportFileForIdentities(GetLatestExportFile(), a);
}

private bool DirectoryExists() => Directory.Exists(FilePaths.PATH_TO_TEMP_DIR);
private bool IdentitiesFileExists() => File.Exists(FilePaths.PATH_TO_IDENTITIES_FILE);
private bool ExportFileExists() => Directory.EnumerateFiles(FilePaths.PATH_TO_TEMP_DIR).Any(FilePaths.EXPORT_FILE_PATTERN.IsMatch);
private string GetLatestExportFile() => Directory.EnumerateFiles(FilePaths.PATH_TO_TEMP_DIR).Where(e => FilePaths.EXPORT_FILE_PATTERN.IsMatch(e)).Max()!;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest a (static?) class AppDirectory (I'm not quite happy with the name, maybe you find a better one), which encapsulates the regular expressions and constants for the file paths and has the following methods:

  • Exists() (only if you want to keep the check for the existence of the directoy)
  • IdentitiesFileExists()
  • ExportFileExists()
  • GetLatestExportFile()


private async Task<string?> GetIdentityToCheck()
{
using var reader = new StreamReader(File.OpenRead(FilePaths.PATH_TO_IDENTITIES_FILE), Encoding.UTF8);

return await reader.ReadLineAsync();
}

private async Task<int> CheckExportFileForIdentities(string exportFile, string identityToCheck)
{
return await AnsiConsole.Progress()
.AutoClear(false)
.HideCompleted(false)
.Columns(
new TaskDescriptionColumn(),
new ProgressBarColumn(),
new PercentageColumn(),
new RemainingTimeColumn(),
new SpinnerColumn(Spinner.Known.Clock)
)
.StartAsync(async ctx =>
{
using var archive = ZipFile.OpenRead(exportFile);

var found = 0;
var tasks = archive.Entries
.Select(e => ctx.AddTask(e.Name, autoStart: false))
.ToList();

foreach (var (index, entry) in archive.Entries.Index())
{
var task = tasks[index];
task.StartTask();
found += await CheckCsvFileForIdentity(entry, identityToCheck, task);
}

return found;
});
}

private async Task<int> CheckCsvFileForIdentity(ZipArchiveEntry file, string identityToCheck, ProgressTask progressReporter)
{
using var reader = new StreamReader(file.Open(), Encoding.UTF8);
List<string> lines = [];
var found = 0;

while (!reader.EndOfStream)
lines.Add(await reader.ReadLineAsync() ?? string.Empty);

progressReporter.MaxValue = lines.Count;

foreach (var line in lines)
{
var count = line
.Split(',')
.Count(s => string.Equals(s, identityToCheck, StringComparison.OrdinalIgnoreCase));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a problem with this solution: if the address is concatenated with something else, it doesn't match. I'd suggest:

Suggested change
var count = line
.Split(',')
.Count(s => string.Equals(s, identityToCheck, StringComparison.OrdinalIgnoreCase));
var count = Regex.Matches(line, identityToCheck).Count


if (count != 0)
AnsiConsole.MarkupLineInterpolated($"[red bold]Found[/] [grey bold]{count}[/] [red bold]occurrences in[/] [grey bold]{file.Name}[/][red bold]:[/] [grey bold]{line}[/]");

found += count;
progressReporter.Increment(1);
}

return found;
}
}
Loading