• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

me-viper / OpaDotNet.Extensions / 6232416674

19 Sep 2023 07:14AM UTC coverage: 90.207% (-1.7%) from 91.902%
6232416674

push

github

me-viper
chore: Minor improvements

64 of 82 branches covered (0.0%)

Branch coverage included in aggregate %.

415 of 449 relevant lines covered (92.43%)

2774.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.32
/src/OpaDotNet.Extensions.AspNetCore/FileSystemPolicySource.cs
1
using Microsoft.Extensions.Options;
2

3
using OpaDotNet.Compilation.Abstractions;
4

5
namespace OpaDotNet.Extensions.AspNetCore;
6

7
public sealed class FileSystemPolicySource : OpaPolicySource
8
{
9
    private readonly FileSystemWatcher _policyWatcher;
10

11
    private readonly PeriodicTimer? _changesMonitor;
12

13
    private readonly CancellationTokenSource _cancellationTokenSource = new();
16✔
14

15
    private bool _needsRecompilation;
16

17
    private bool MonitoringEnabled => Options.Value.MonitoringInterval > TimeSpan.Zero;
33✔
18

19
    public FileSystemPolicySource(
20
        IRegoCompiler compiler,
21
        IOptions<OpaAuthorizationOptions> options,
22
        ILoggerFactory loggerFactory) : base(compiler, options, loggerFactory)
16✔
23
    {
16✔
24
        if (string.IsNullOrWhiteSpace(options.Value.PolicyBundlePath))
16!
25
            throw new InvalidOperationException("Compiler requires OpaAuthorizationOptions.PolicyBundlePath specified");
×
26

27
        _policyWatcher = new()
16✔
28
        {
16✔
29
            Path = Options.Value.PolicyBundlePath!,
16✔
30
            Filters = { "*.rego", "data.json", "data.yaml" },
16✔
31
            NotifyFilter = NotifyFilters.LastWrite,
16✔
32
            IncludeSubdirectories = true,
16✔
33
        };
16✔
34

35
        if (MonitoringEnabled)
16✔
36
        {
1✔
37
            _policyWatcher.Changed += PolicyChanged;
1✔
38
            _changesMonitor = new(Options.Value.MonitoringInterval);
1✔
39
        }
1✔
40
    }
16✔
41

42
    protected override async Task<Stream?> CompileBundleFromSource(bool recompiling, CancellationToken cancellationToken = default)
43
    {
119✔
44
        return await Compiler.CompileBundle(
119✔
45
            Options.Value.PolicyBundlePath!,
119✔
46
            cancellationToken: cancellationToken,
119✔
47
            entrypoints: Options.Value.Entrypoints
119✔
48
            ).ConfigureAwait(false);
119✔
49
    }
119✔
50

51
    private void PolicyChanged(object sender, FileSystemEventArgs e)
52
    {
6✔
53
        if (_cancellationTokenSource.Token.IsCancellationRequested)
6✔
54
            return;
×
55

56
        Logger.LogDebug(
6✔
57
            "Detected policy change {Change} in {File}. Stashing until next recompilation cycle",
6✔
58
            e.ChangeType,
6✔
59
            e.FullPath
6✔
60
            );
6✔
61

62
        _needsRecompilation = true;
6✔
63
    }
6✔
64

65
    private async Task TrackPolicyChanged(CancellationToken cancellationToken)
66
    {
1✔
67
        if (!MonitoringEnabled || _changesMonitor == null)
1!
68
            return;
×
69

70
        Logger.LogDebug("Watching for policy changes in {Path}", Options.Value.PolicyBundlePath);
1✔
71

72
        while (await _changesMonitor.WaitForNextTickAsync(cancellationToken).ConfigureAwait(false))
6!
73
        {
5✔
74
            try
75
            {
5✔
76
                if (!_needsRecompilation)
5✔
77
                    continue;
2✔
78

79
                if (cancellationToken.IsCancellationRequested)
3!
80
                    break;
×
81

82
                _needsRecompilation = false;
3✔
83

84
                Logger.LogDebug("Detected changes. Recompiling");
3✔
85
                await CompileBundle(true, cancellationToken).ConfigureAwait(false);
3✔
86
                Logger.LogDebug("Recompilation succeeded");
3✔
87
            }
3✔
88
            catch (Exception ex)
×
89
            {
×
90
                Logger.LogError(ex, "Failed to process policy changes");
×
91
                _needsRecompilation = true;
×
92
            }
×
93
        }
3✔
94

95
        Logger.LogDebug("Stopped watching for policy changes");
×
96
    }
×
97

98
    protected override void Dispose(bool disposing)
99
    {
2✔
100
        try
101
        {
2✔
102
            if (disposing)
2✔
103
            {
2✔
104
                _changesMonitor?.Dispose();
2✔
105
                _policyWatcher.Dispose();
2✔
106
                _cancellationTokenSource.Dispose();
2✔
107
            }
2✔
108
        }
2✔
109
        finally
110
        {
2✔
111
            base.Dispose(disposing);
2✔
112
        }
2✔
113
    }
2✔
114

115
    /// <inheritdoc/>
116
    public override async Task StartAsync(CancellationToken cancellationToken)
117
    {
16✔
118
        await base.StartAsync(cancellationToken).ConfigureAwait(false);
16✔
119

120
        if (MonitoringEnabled)
16✔
121
        {
1✔
122
            _policyWatcher.EnableRaisingEvents = true;
1✔
123
            _ = Task.Run(() => TrackPolicyChanged(_cancellationTokenSource.Token), cancellationToken);
2✔
124
        }
1✔
125
    }
16✔
126

127
    /// <inheritdoc/>
128
    public override async Task StopAsync(CancellationToken cancellationToken)
129
    {
2✔
130
        await base.StopAsync(cancellationToken).ConfigureAwait(false);
2✔
131

132
        _policyWatcher.EnableRaisingEvents = false;
2✔
133
        _cancellationTokenSource.Cancel();
2✔
134
        Logger.LogDebug("Stopped");
2✔
135
    }
2✔
136
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc