Skip to content

Commit 7db3cdc

Browse files
authored
Updated CLI and Templates (#5)
1 parent 3e8a319 commit 7db3cdc

File tree

4 files changed

+93
-65
lines changed

4 files changed

+93
-65
lines changed

tenint/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
from .models.configuration import Configuration, Settings # noqa F401
33
from .connector import Connector # noqa F401
44

5-
__version__ = "0.9.0"
5+
__version__ = '0.9.1'

tenint/cli.py

+57-54
Original file line numberDiff line numberDiff line change
@@ -12,124 +12,127 @@
1212
from tenint.models.pyproject import PyProject
1313

1414
console = Console()
15-
tmpl = Path(os.path.dirname(__file__)).joinpath('templates')
15+
tmpl = Path(os.path.dirname(__file__)).joinpath("templates")
1616
app = Typer()
1717

1818

19-
@app.command('init')
19+
@app.command("init")
2020
def init_connector(
2121
path: Annotated[
22-
Path, Option(help='initialization path', dir_okay=True, file_okay=False)
23-
] = Path('.'),
22+
Path, Option(help="initialization path", dir_okay=True, file_okay=False)
23+
] = Path("."),
2424
):
2525
is_dirty = False
26-
for fn in ('pyproject.toml', 'connector.py'):
26+
for fn in ("pyproject.toml", "connector.py"):
2727
src = tmpl.joinpath(fn)
2828
dest = path.joinpath(fn)
2929

3030
if dest.exists():
3131
console.print(
32-
f'[yellow bold]WARNING[/yellow bold]: skipped '
33-
f'existing [cyan]{dest}[/cyan] as it already exists'
32+
f"[yellow bold]WARNING[/yellow bold]: skipped "
33+
f"existing [cyan]{dest}[/cyan] as it already exists"
3434
)
3535
is_dirty = True
3636
else:
37-
with src.open('rb') as sobj, dest.open('wb') as dobj:
37+
with src.open("rb") as sobj, dest.open("wb") as dobj:
3838
dobj.write(sobj.read())
3939

40-
tests = path.joinpath('tests')
40+
tests = path.joinpath("tests")
4141
if not tests.exists():
4242
tests.mkdir()
43-
src = tmpl.joinpath('test_connector.py')
44-
dest = tests.joinpath('test_connector.py')
45-
with dest.open('wb') as dobj, src.open('rb') as sobj:
43+
src = tmpl.joinpath("test_connector.py")
44+
dest = tests.joinpath("test_connector.py")
45+
with dest.open("wb") as dobj, src.open("rb") as sobj:
4646
dobj.write(sobj.read())
4747
else:
4848
console.print(
49-
'[yellow bold]NOTE[/yellow bold]: skipped adding tests. tests folder exists.'
49+
"[yellow bold]NOTE[/yellow bold]: skipped adding tests. tests folder exists."
5050
)
5151

5252
console.print(
5353
Panel(
54-
'Now that you have an initialized tenint connector, please review the '
55-
'files that have been created for your next steps.\n\n'
56-
'- [bold cyan]pyproject.toml[/bold cyan] contains the project '
57-
' requirements and is used to build the marketplace files\n'
58-
'- [bold cyan]connector.py[/bold cyan] is a sample connector '
59-
'to get you started. It contains some example settings, a '
60-
'credential example, and a sample function.',
61-
title='[bold cyan]Tenable Integration Framework Connector[/bold cyan]',
54+
"Now that you have an initialized tenint connector, please review the "
55+
"files that have been created for your next steps.\n\n"
56+
"- [bold cyan]pyproject.toml[/bold cyan] contains the project "
57+
" requirements and is used to build the marketplace files\n"
58+
"- [bold cyan]connector.py[/bold cyan] is a sample connector "
59+
"to get you started. It contains some example settings, a "
60+
"credential example, and a sample function.",
61+
title="[bold cyan]Tenable Integration Framework Connector[/bold cyan]",
6262
)
6363
)
6464
if is_dirty:
6565
console.print(
6666
Panel(
67-
'Could not initialize all of the files as some appeared to already '
68-
'exist. Any files that previously existed were not modified. '
69-
'Recommend manually reviewing your project to ensure everything '
70-
'looks correct.',
71-
title='[bold red]Dirty Environment Warning[/bold red]',
72-
style='yellow',
67+
"Could not initialize all of the files as some appeared to already "
68+
"exist. Any files that previously existed were not modified. "
69+
"Recommend manually reviewing your project to ensure everything "
70+
"looks correct.",
71+
title="[bold red]Dirty Environment Warning[/bold red]",
72+
style="yellow",
7373
)
7474
)
7575

7676

77-
@app.command('build')
77+
@app.command("build")
7878
def build_connector(
79-
path: Annotated[Path, Option(help='connector code path')] = Path('.'),
80-
platform: Annotated[str | None, Option(help='platform to build to')] = None,
79+
path: Annotated[Path, Option(help="connector code path")] = Path("."),
80+
platform: Annotated[str | None, Option(help="platform to build to")] = None,
8181
tag: Annotated[
8282
str | None,
83-
Option(
84-
help='Tag for the fimal image. Defaults to the image settings if unspecified.'
85-
),
83+
Option(help="Tag for the fimal image. defaults to the project name."),
8684
] = None,
8785
cleanup: Annotated[
88-
bool | None, Option(help='auto-remove any generated build files?')
86+
bool | None, Option(help="auto-remove any generated build files?")
8987
] = None,
9088
):
91-
tmpldfile = tmpl.joinpath('Dockerfile')
92-
dockerfile = path.joinpath('Dockerfile')
93-
pyproject = path.joinpath('pyproject.toml')
89+
tmpldfile = tmpl.joinpath("Dockerfile")
90+
dockerfile = path.joinpath("Dockerfile")
91+
pyproject = path.joinpath("pyproject.toml")
9492

9593
if not tag:
96-
with pyproject.open('rb') as pf:
94+
with pyproject.open("rb") as pf:
9795
project = PyProject(**tomllib.load(pf))
98-
tag = project.tool.tenint.connector.images.amd64
96+
tag = project.project.name
9997

10098
if not dockerfile.exists():
101-
with tmpldfile.open('rb') as src, dockerfile.open('wb') as dst:
99+
with tmpldfile.open("rb") as src, dockerfile.open("wb") as dst:
102100
dst.write(src.read())
103101
cleanup = True if cleanup is None else cleanup
104102

105103
builder = subprocess.Popen(
106-
['docker', 'build', '-t', tag, path],
104+
["docker", "build", "-t", tag, path],
107105
stdout=subprocess.PIPE,
108106
stderr=subprocess.STDOUT,
109107
)
110108
for line in builder.stdout:
111-
console.out(line.decode('utf-8').strip('\n'))
109+
console.out(line.decode("utf-8").strip("\n"))
112110

113111
if cleanup:
114112
dockerfile.unlink()
115113

116114

117-
@app.command('marketplace')
115+
@app.command("marketplace")
118116
def gen_marketplace(
119-
image: Annotated[
120-
str, Option(..., help='Docker Image Name')
121-
] = 'local/connector-example',
117+
image: Annotated[str, Option(..., help="Docker Image Name")] = None,
122118
icon: Annotated[
123-
str, Option(..., help='Icon Image URL')
124-
] = 'https://nourl.example/logo.svg',
125-
path: Annotated[Path, Option(help='connector code path')] = Path('.'),
126-
output: Annotated[Path, Option(help='output marketplace json file')] = None,
119+
str, Option(..., help="Icon Image URL")
120+
] = "https://nourl.example/logo.svg",
121+
path: Annotated[Path, Option(help="connector code path")] = Path("."),
122+
output: Annotated[Path, Option(help="output marketplace json file")] = None,
127123
):
128-
mpfile = path.joinpath('marketplace-object.json')
124+
pyproject_file = path.joinpath("pyproject.toml")
125+
with pyproject_file.open("rb") as fobj:
126+
project = PyProject(**tomllib.load(fobj))
127+
128+
if not image:
129+
image = project.project.name
130+
131+
mpfile = path.joinpath("marketplace-object.json")
129132
mp = MarketplaceConnector.load_from_pyproject(
130-
filename='pyproject.toml', image_url=image, icon_url=icon
131-
).model_dump(mode='json')
133+
filename=project, image_url=image, icon_url=icon
134+
).model_dump(mode="json")
132135
console.print(mp)
133136
if output:
134-
with mpfile.open('w', encoding='utf-8') as fobj:
137+
with mpfile.open("w", encoding="utf-8") as fobj:
135138
fobj.write(mp.model_dump_json())

tenint/templates/Dockerfile

+22-10
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
1-
FROM python:3.12-alpine AS build
2-
RUN pip install uv && uv pip install --system tenint
3-
RUN addgroup -S connector && adduser connector -S -G connector -h /connector
1+
FROM python:3.12-alpine AS connector-base
2+
3+
ARG UV_SYSTEM_PYTHON=true
4+
RUN pip install uv && uv pip install tenint
45

5-
ADD --chown=connector:connector ./ /connector/
66

7-
RUN uv pip install --system -r /connector/pyproject.toml
7+
FROM connector-base AS build
8+
ADD ./ /connector/
9+
RUN uv pip install -r /connector/pyproject.toml
810

911

1012
FROM build AS test
1113
WORKDIR /connector/
12-
RUN uv pip install --system "tenint[testing]" \
13-
&& uv pip install --system --extra testing -r /connector/pyproject.toml
14+
RUN uv pip install "tenint[testing]" \
15+
&& uv pip install --extra testing -r /connector/pyproject.toml
1416
RUN ruff check
15-
RUN python -m pytest
17+
RUN python -m pytest --cov-fail-under=80
1618
RUN uv export --format requirements-txt | uv tool run pip-audit
1719
RUN uv tool run \
1820
--with "bandit[toml,baseline,sarif]" \
1921
bandit -c pyproject.toml -r . -ll
2022
RUN tenint marketplace
23+
RUN echo $(date '+Y-%m-%d %H:%M%S') > /tested_on
24+
25+
26+
FROM python:3.12-alpine
2127

22-
FROM build AS release
28+
RUN addgroup -S connector && adduser connector -S -G connector -h /connector
29+
USER connector:connector
2330
WORKDIR /connector/
24-
COPY --from=test --chown=connector:connector /connector/marketplace.json marketplace.json
31+
32+
COPY --from=connector-base /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
33+
COPY --from=build /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
34+
COPY --from=build --chown=connector:connector /connector /connector
35+
COPY --from=test --chown=connector:connector /tested_on /tested_on
36+
2537
ENTRYPOINT ["python", "connector.py"]

tenint/templates/test_connector.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import connector
2+
from typer.testing import CliRunner
3+
4+
runner = CliRunner()
5+
6+
7+
def test_connector_run():
8+
result = runner.invoke(
9+
connector.connector.app, ["run", "-l", "INFO", "-j", '{"is_bool": true}']
10+
)
11+
print(result.stdout)
12+
assert result.exit_code == 0
13+
assert "hello world" in result.stdout

0 commit comments

Comments
 (0)