forked from admin/VolcanicAgenticCore
feat(telegram): process environment policy, secret values and host hardening
Spec 6 now says this spec adds only the bot token to SecretValues; the speech key and Google client secret are added by the telegram-attachments and google-calendar specs.
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
using Volcanic.AgenticCore.Features.Processes;
|
||||
|
||||
namespace Volcanic.AgenticCore.Telegram;
|
||||
|
||||
/// <summary>The <c>ProcessEnvironment</c> configuration section. Its lists are added to the core defaults, not replacing them.</summary>
|
||||
public sealed class ProcessEnvironmentSection
|
||||
{
|
||||
public const string SectionName = "ProcessEnvironment";
|
||||
public List<string> Deny { get; set; } = [];
|
||||
public List<string> Allow { get; set; } = [];
|
||||
public bool HardenHostProcess { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>The Telegram host's process environment: section, <c>PROCESS_ENV_ALLOW</c> and the host's secret values.</summary>
|
||||
public static class TelegramProcessEnvironment
|
||||
{
|
||||
public const string AllowVariable = "PROCESS_ENV_ALLOW";
|
||||
|
||||
/// <summary>Adds the section's lists, <c>PROCESS_ENV_ALLOW</c> and the bot token to <paramref name="target"/>.</summary>
|
||||
public static void Configure(ProcessEnvironmentOptions target, TelegramOptions telegram, ProcessEnvironmentSection section, Func<string, string?> getEnv)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(target);
|
||||
ArgumentNullException.ThrowIfNull(telegram);
|
||||
ArgumentNullException.ThrowIfNull(section);
|
||||
ArgumentNullException.ThrowIfNull(getEnv);
|
||||
target.Deny.AddRange(section.Deny);
|
||||
target.Allow.AddRange(section.Allow);
|
||||
if (getEnv(AllowVariable) is { Length: > 0 } allow)
|
||||
target.Allow.AddRange(allow.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
|
||||
target.HardenHostProcess = section.HardenHostProcess;
|
||||
if (!string.IsNullOrWhiteSpace(telegram.BotToken)) target.SecretValues.Add(telegram.BotToken);
|
||||
}
|
||||
|
||||
/// <summary>The startup log line: names only, never values.</summary>
|
||||
public static string Describe(ProcessEnvironmentOptions options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
return $"Process environment: {options.Deny.Count} deny rules, allow: {(options.Allow.Count == 0 ? "none" : string.Join(", ", options.Allow))}";
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegram.Bot;
|
||||
using Volcanic.AgenticCore.Extensions.ClaudeCode;
|
||||
using Volcanic.AgenticCore.Features.Processes;
|
||||
using Volcanic.AgenticCore.Hosting;
|
||||
using Volcanic.AgenticCore.Telegram;
|
||||
using Volcanic.AgenticCore.Telegram.Chats;
|
||||
@@ -18,7 +19,10 @@ var builder = Host.CreateApplicationBuilder(args);
|
||||
|
||||
var options = builder.Configuration.GetSection(TelegramOptions.SectionName).Get<TelegramOptions>() ?? new TelegramOptions();
|
||||
options.ApplyEnvironment(Environment.GetEnvironmentVariable);
|
||||
var errors = options.Validate();
|
||||
var processSection = builder.Configuration.GetSection(ProcessEnvironmentSection.SectionName).Get<ProcessEnvironmentSection>() ?? new ProcessEnvironmentSection();
|
||||
var processEnvironment = new ProcessEnvironmentOptions();
|
||||
TelegramProcessEnvironment.Configure(processEnvironment, options, processSection, Environment.GetEnvironmentVariable);
|
||||
var errors = options.Validate().Concat(processEnvironment.Validate()).ToList();
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
foreach (var error in errors) Console.Error.WriteLine(error);
|
||||
@@ -37,6 +41,7 @@ builder.Services.AddSingleton(sp => new ClaudeCodeProviderOptions
|
||||
builder.Services.AddAgenticCore(o =>
|
||||
{
|
||||
o.DefaultModel = options.Model;
|
||||
o.ProcessEnvironment = processEnvironment;
|
||||
o.AddExtension<ClaudeCodeProviderExtension>();
|
||||
});
|
||||
builder.Services.AddSingleton<ITelegramBotClient>(_ => new TelegramBotClient(options.BotToken));
|
||||
@@ -52,6 +57,9 @@ builder.Services.AddHostedService<BotSetupService>();
|
||||
using var host = builder.Build();
|
||||
|
||||
var logger = host.Services.GetRequiredService<ILoggerFactory>().CreateLogger("Volcanic.AgenticCore.Telegram");
|
||||
// Before polling and the first claude process; the spawn policy's own call later is a no-op.
|
||||
HostProcessHardening.Apply(processEnvironment, logger);
|
||||
logger.LogInformation("{ProcessEnvironment}", TelegramProcessEnvironment.Describe(processEnvironment));
|
||||
if (ClaudeInstallation.Locate(Environment.GetEnvironmentVariable) is { } claude)
|
||||
logger.LogInformation("Using Claude Code at {Path}, model {Model}", claude, options.Model);
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user