Skip to content

Reference

sopsy

SOPSy, a Python wrapper around SOPS.

SOPS binary must be installed and available in your $PATH.

Sops

Sops(
    file: str | Path,
    *,
    binary_path: str | Path | None = None,
    config: str | Path | None = None,
    config_dict: dict[str, Any] | None = None,
    extract: str | None = None,
    in_place: bool = False,
    input_type: str | SopsyInOutType | None = None,
    output: str | Path | None = None,
    output_type: str | SopsyInOutType | None = None
)

SOPS file object.

Attributes:

Name Type Description
file Path

Path to the SOPS file.

global_args list[str]

The list of arguments that will be passed to the sops shell command. It can be used to customize it. Use it only if you know what you are doing.

Examples:

>>> from pathlib import Path
>>> from sopsy import Sops
>>> sops = Sops(
>>>     binary_path="/app/bin/my_custom_sops",
>>>     config=Path(".config/sops.yml"),
>>>     file=Path("secrets.json"),
>>> )

Parameters:

Name Type Description Default
file str | Path

Path to the SOPS file.

required
config str | Path | None

Path to a custom SOPS config file.

None
config_dict dict[str, Any] | None

Allow to pass SOPS config as a python dict.

None
extract str | None

Extract a specific key or branch from the input document.

None
in_place bool

Write output back to the same file instead of stdout.

False
input_type str | SopsyInOutType | None

If not set, sops will use the file's extension to determine the type.

None
output str | Path | None

Save the output after encryption or decryption to the file specified.

None
output_type str | SopsyInOutType | None

If not set, sops will use the input file's extension to determine the output format.

None
binary_path str | Path | None

Path to the SOPS binary. If not defined it will search for it in the PATH environment variable.

None
Source code in src/sopsy/sopsy.py
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def __init__(
    self,
    file: str | Path,
    *,
    binary_path: str | Path | None = None,
    config: str | Path | None = None,
    config_dict: dict[str, Any] | None = None,
    extract: str | None = None,
    in_place: bool = False,
    input_type: str | SopsyInOutType | None = None,
    output: str | Path | None = None,
    output_type: str | SopsyInOutType | None = None,
) -> None:
    """Initialize SOPS object.

    Examples:
        >>> from pathlib import Path
        >>> from sopsy import Sops
        >>> sops = Sops(
        >>>     binary_path="/app/bin/my_custom_sops",
        >>>     config=Path(".config/sops.yml"),
        >>>     file=Path("secrets.json"),
        >>> )

    Args:
        file: Path to the SOPS file.
        config: Path to a custom SOPS config file.
        config_dict: Allow to pass SOPS config as a python dict.
        extract: Extract a specific key or branch from the input document.
        in_place: Write output back to the same file instead of stdout.
        input_type: If not set, sops will use the file's extension to determine
            the type.
        output: Save the output after encryption or decryption to the file
            specified.
        output_type: If not set, sops will use the input file's extension to
            determine the output format.
        binary_path: Path to the SOPS binary. If not defined it will search for it
            in the PATH environment variable.
    """
    self.bin: Path = Path("sops")
    self.file: Path = Path(file).resolve(strict=True)
    self.global_args: list[str] = []
    if binary_path:
        self.bin = Path(binary_path)
    if extract:
        self.global_args.extend(["--extract", extract])
    if in_place:
        self.global_args.extend(["--in-place"])
    if input_type:
        self.global_args.extend(["--input-type", str(input_type)])
    if output:
        self.global_args.extend(["--output", str(output)])
    if output_type:
        self.global_args.extend(["--output-type", str(output_type)])

    if isinstance(config, str):
        config = Path(config)
    if config_dict is None:
        config_dict = {}
    config_dict = build_config(config_path=config, config_dict=config_dict)
    with tempfile.NamedTemporaryFile(mode="w", delete=False) as fp:
        yaml.dump(config_dict, fp)
        config_tmp = fp.name
    self.global_args.extend(["--config", config_tmp])

    if not shutil.which(self.bin):
        msg = (
            f"{self.bin} command not found, "
            "you may need to install it and/or add it to your PATH"
        )
        raise SopsyCommandNotFoundError(msg)

decrypt

decrypt(*, to_dict: bool = True) -> bytes | dict[str, Any] | None

Decrypt SOPS file.

Examples:

>>> from sopsy import Sops, SopsyInOutType
>>> sops = Sops("secrets.json", output_type=SopsyInOutType.YAML)
>>> sops.decrypt(to_dict=False)
hello: world

Parameters:

Name Type Description Default
to_dict bool

Return the output as a Python dict.

True

Returns:

Type Description
bytes | dict[str, Any] | None

The output of the sops command.

Source code in src/sopsy/sopsy.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def decrypt(self, *, to_dict: bool = True) -> bytes | dict[str, Any] | None:
    """Decrypt SOPS file.

    Examples:
        >>> from sopsy import Sops, SopsyInOutType
        >>> sops = Sops("secrets.json", output_type=SopsyInOutType.YAML)
        >>> sops.decrypt(to_dict=False)
        hello: world

    Args:
        to_dict: Return the output as a Python dict.

    Returns:
        The output of the sops command.
    """
    cmd = [str(self.bin), "--decrypt", *self.global_args, str(self.file)]
    return run_cmd(cmd, to_dict=to_dict)

encrypt

encrypt(*, to_dict: bool = True) -> bytes | dict[str, Any] | None

Encrypt SOPS file.

Examples:

>>> import json
>>> from pathlib import Path
>>> from sopsy import Sops
>>> secrets = Path("secrets.json")
>>> secrets.write_text(json.dumps({"hello": "world"}))
>>> sops = Sops(secrets, in_place=True)
>>> sops.encrypt()

Parameters:

Name Type Description Default
to_dict bool

Return the output as a Python dict.

True

Returns:

Type Description
bytes | dict[str, Any] | None

The output of the sops command.

Source code in src/sopsy/sopsy.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
def encrypt(self, *, to_dict: bool = True) -> bytes | dict[str, Any] | None:
    """Encrypt SOPS file.

    Examples:
        >>> import json
        >>> from pathlib import Path
        >>> from sopsy import Sops
        >>> secrets = Path("secrets.json")
        >>> secrets.write_text(json.dumps({"hello": "world"}))
        >>> sops = Sops(secrets, in_place=True)
        >>> sops.encrypt()

    Args:
        to_dict: Return the output as a Python dict.

    Returns:
        The output of the sops command.
    """
    cmd = [str(self.bin), "--encrypt", *self.global_args, str(self.file)]
    return run_cmd(cmd, to_dict=to_dict)

get

get(key: str, *, default: Any = None) -> Any

Get a specific key from a SOPS encrypted file.

Examples:

>>> from sopsy import Sops
>>> sops = Sops("secrets.json")
>>> sops.get("hello")
b'world'
>>> sops.get("nonexistent", default="DefaultValue")
'DefaultValue'

Parameters:

Name Type Description Default
key str

The key to fetch in the SOPS file content.

required
default Any

A default value in case the key does not exist or is empty.

None

Returns:

Type Description
Any

The value of the given key, or the default value.

Source code in src/sopsy/sopsy.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def get(self, key: str, *, default: Any = None) -> Any:  # noqa: ANN401
    """Get a specific key from a SOPS encrypted file.

    Examples:
        >>> from sopsy import Sops
        >>> sops = Sops("secrets.json")
        >>> sops.get("hello")
        b'world'
        >>> sops.get("nonexistent", default="DefaultValue")
        'DefaultValue'

    Args:
        key: The key to fetch in the SOPS file content.
        default: A default value in case the key does not exist or is empty.

    Returns:
        The value of the given key, or the default value.
    """
    data: dict[Any, Any] = self.decrypt()  # pyright: ignore[reportAssignmentType]
    return data.get(key) or default

rotate

rotate(*, to_dict: bool = True) -> bytes | dict[str, Any] | None

Rotate encryption keys and re-encrypt values from SOPS file.

Examples:

>>> from sopsy import Sops
>>> sops = Sops("secrets.json", in_place=True)
>>> sops.rotate()

Parameters:

Name Type Description Default
to_dict bool

Return the output as a Python dict.

True

Returns:

Type Description
bytes | dict[str, Any] | None

The output of the sops command.

Source code in src/sopsy/sopsy.py
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
def rotate(self, *, to_dict: bool = True) -> bytes | dict[str, Any] | None:
    """Rotate encryption keys and re-encrypt values from SOPS file.

    Examples:
        >>> from sopsy import Sops
        >>> sops = Sops("secrets.json", in_place=True)
        >>> sops.rotate()

    Args:
        to_dict: Return the output as a Python dict.

    Returns:
        The output of the sops command.
    """
    cmd = [str(self.bin), "--rotate", *self.global_args, str(self.file)]
    return run_cmd(cmd, to_dict=to_dict)

SopsyCommandFailedError

Bases: SopsyError

Sopsy could not execute SOPS command successfully.

SopsyCommandNotFoundError

Bases: SopsyError

Sopsy could not find SOPS command in PATH.

SopsyConfigNotFoundError

Bases: SopsyError

Sopsy could not find the given configuration file.

SopsyError

Bases: Exception

Sopsy base exception class.

SopsyInOutType

Bases: Enum

SOPS output types.

Intend to be passed on Sops().input_type and Sops().output_type.

Attributes:

Name Type Description
BINARY str

Binary type.

DOTENV str

DotEnv type.

JSON str

JSON type.

YAML str

YAML type.

SopsyUnparsableOutpoutTypeError

Bases: SopsyError

Sopsy could not read SOPS output content.