fix: finish progressive Target detection

This commit is contained in:
proxyctl coordinator
2026-07-17 21:25:43 +08:00
parent ad651402fd
commit 8348fa3ac8
17 changed files with 672 additions and 221 deletions
+39 -13
View File
@@ -155,32 +155,54 @@ func (a *Adapter) DiagnosticChecks(ctx context.Context, _ *profile.Profile) []ta
}
func (a *Adapter) Availability(ctx context.Context) target.Availability {
availability, _ := a.detectAvailability(ctx)
availability, _, _ := a.detectAvailability(ctx)
return availability
}
func (a *Adapter) detectAvailability(ctx context.Context) (target.Availability, error) {
// detectAvailability returns the effective dump used to prove capability so a
// progressive Detect can classify state without running apt-config twice.
func (a *Adapter) detectAvailability(ctx context.Context) (target.Availability, []byte, error) {
marker, err := os.Stat(a.configuration.DebianVersionFile)
if err != nil || !marker.Mode().IsRegular() {
return target.Availability{Evidence: "Debian-family marker /etc/debian_version was not detected"}, nil
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return target.Availability{Evidence: "Debian-family marker /etc/debian_version was not detected"}, nil, nil
}
return target.Availability{Evidence: "Debian-family marker /etc/debian_version could not be inspected"}, nil, fmt.Errorf("inspect Debian-family marker: %w", err)
}
if !marker.Mode().IsRegular() {
return target.Availability{Evidence: "Debian-family marker /etc/debian_version was not detected"}, nil, nil
}
directory, err := os.Stat(a.configuration.ConfigDirectory)
if err != nil || !directory.IsDir() {
return target.Availability{Evidence: "APT configuration directory apt.conf.d was not detected"}, nil
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return target.Availability{Evidence: "APT configuration directory apt.conf.d was not detected"}, nil, nil
}
return target.Availability{Evidence: "APT configuration directory apt.conf.d could not be inspected"}, nil, fmt.Errorf("inspect APT configuration directory: %w", err)
}
if !directory.IsDir() {
return target.Availability{Evidence: "APT configuration directory apt.conf.d was not detected"}, nil, nil
}
command, err := a.runner.LookPath("apt-config")
if err != nil {
return target.Availability{Evidence: "Debian APT tool apt-config was not detected"}, nil
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, exec.ErrNotFound) {
return target.Availability{Evidence: "Debian APT tool apt-config was not detected"}, nil, nil
}
return target.Availability{Evidence: "Debian APT tool apt-config could not be inspected"}, nil, fmt.Errorf("locate apt-config: %w", err)
}
if _, err := a.runner.Output(ctx, command, "dump"); err != nil {
return target.Availability{Evidence: "apt-config could not inspect effective APT configuration"}, fmt.Errorf("inspect effective APT configuration: %w", err)
effective, err := a.runner.Output(ctx, command, "dump")
if err != nil {
return target.Availability{Evidence: "apt-config could not inspect effective APT configuration"}, nil, fmt.Errorf("inspect effective APT configuration: %w", err)
}
return target.Availability{Available: true, Evidence: "Debian marker, apt-config, and apt.conf.d configuration capability detected"}, nil
return target.Availability{Available: true, Evidence: "Debian marker, apt-config, and apt.conf.d configuration capability detected"}, effective, nil
}
func (a *Adapter) Detect(ctx context.Context, active *profile.Profile) target.Detection {
availability, availabilityErr := a.detectAvailability(ctx)
inspection, inspectionErr := a.inspect(ctx, active)
availability, effective, availabilityErr := a.detectAvailability(ctx)
if !availability.Available && availabilityErr == nil {
return target.Detection{Availability: availability}
}
overlay, overlayErr := a.files.ReadFile(a.configuration.OverlayFile)
inspection, inspectionErr := a.inspectObserved(active, overlay, overlayErr, effective, availabilityErr)
return target.Detection{Availability: availability, Inspection: inspection, Err: errors.Join(availabilityErr, inspectionErr)}
}
@@ -193,11 +215,15 @@ func (a *Adapter) Inspect(ctx context.Context, active *profile.Profile) target.I
func (a *Adapter) inspect(ctx context.Context, active *profile.Profile) (target.Inspection, error) {
overlay, overlayErr := a.files.ReadFile(a.configuration.OverlayFile)
effective, dumpErr := a.dump(ctx)
return a.inspectObserved(active, overlay, overlayErr, effective, dumpErr)
}
func (a *Adapter) inspectObserved(active *profile.Profile, overlay []byte, overlayErr error, effective []byte, dumpErr error) (target.Inspection, error) {
managed := overlayErr == nil && isOwnedOverlay(overlay)
if overlayErr != nil && !errors.Is(overlayErr, fs.ErrNotExist) {
return target.Inspection{State: target.Drifted, Evidence: "managed APT overlay cannot be read"}, fmt.Errorf("read managed APT overlay: %w", overlayErr)
}
effective, dumpErr := a.dump(ctx)
if dumpErr != nil {
if managed {
return target.Inspection{State: target.Drifted, Evidence: "managed APT overlay exists but effective configuration cannot be inspected"}, dumpErr
+15
View File
@@ -46,6 +46,19 @@ func TestAvailabilityRequiresDebianMarkerAPTToolAndConfigurationDirectory(t *tes
}
}
func TestDetectClassifiesInspectionFailureAndUsesOneEffectiveConfigurationProbe(t *testing.T) {
a, runner := newAdapter(t, nil)
runner.outputError = true
detection := a.Detect(context.Background(), compatibleProfile())
if detection.Err == nil || detection.Inspection.State != target.Disabled {
t.Fatalf("detection = %#v, want failed Disabled inspection", detection)
}
if runner.outputs != 1 {
t.Fatalf("Detect issued %d apt-config dumps, want one", runner.outputs)
}
}
func TestDiagnosticChecksCoverCommandSchemaAndAuthorityWithoutMutation(t *testing.T) {
a, _ := newAdapter(t, nil)
checks := a.DiagnosticChecks(context.Background(), compatibleProfile())
@@ -442,6 +455,7 @@ func newFailingAdapter(t *testing.T, files *failingFS) (*apt.Adapter, *fakeRunne
type fakeRunner struct {
available, outputError bool
overlay, external, override, failDumpAfterWrite string
outputs int
}
func (r *fakeRunner) LookPath(string) (string, error) {
@@ -451,6 +465,7 @@ func (r *fakeRunner) LookPath(string) (string, error) {
return "/usr/bin/apt-config", nil
}
func (r *fakeRunner) Output(context.Context, string, ...string) ([]byte, error) {
r.outputs++
if r.outputError {
return nil, errors.New("apt-config dump failed")
}