GeoGenius.Pipeline.CommandAllowlist (geo_genius v0.2.0)

Copy Markdown View Source

The GeoGenius.Command the import pipeline hands a provider: the configured command adapter, narrowed to the one executable a shipped provider needs.

A provider is given a command adapter by design -- GeoGenius.Providers.Shapefile converts its archive with ogr2ogr -- but GeoGenius.Command.run/3 takes an arbitrary executable with arbitrary arguments, and both ogr2ogr -f PostgreSQL PG:... and psql write to the very database the catalog lives in. Narrowing the adapter the pipeline passes means a provider that reaches for something else is refused by name rather than obeyed.

This is a guardrail, not a sandbox. It bounds what a provider does by accident or by copying an example; it cannot bound what a provider does deliberately. Nothing stops provider code from calling GeoGenius.Commands.System directly, resolving the configured adapter itself out of application environment, or reading the adapter this wraps out of opts[:command_target] -- which is there because a caller must be able to substitute an adapter per call, including in tests. Elixir has no module-level enforcement to offer here, so, exactly as with the rest of GeoGenius.Provider's contract, a provider that only parses is a discipline the pipeline and the tests hold providers to rather than a guarantee this module can make.

run/3 refuses anything but ogr2ogr with an error naming the rejected executable, using the shell's own 126 ("found, not executable") so a provider formats it the same way it formats any other failed command. available?/2 answers false for a refused executable rather than reporting what is on the search path, so a provider that probes before running gets the same answer either way.

The adapter this wraps comes from opts[:command_target], falling back to the configured adapter. Configuring this module as the host's command adapter would make that fallback resolve to itself and recurse forever, with no error and no output -- an import that simply hangs -- so it raises instead. The options it forwards have :command and :command_target removed, so a host's own adapter never receives this module's private vocabulary.

Summary

Functions

Whether an allowed executable is on the search path; false for a refused one.

Runs an allowed executable through the wrapped adapter, refusing every other one.

Functions

available?(executable, opts)

@spec available?(String.t(), keyword()) :: boolean()

Whether an allowed executable is on the search path; false for a refused one.

run(executable, args, opts)

@spec run(String.t(), [String.t()], keyword()) ::
  {:ok, String.t()} | {:error, {integer(), String.t()}}

Runs an allowed executable through the wrapped adapter, refusing every other one.