# cmdbox (Command Development Application)
- It is a command development application with a plugin mechanism.
- Documentation is [here](https://hamacom2004jp.github.io/cmdbox/).
- With cmdbox, you can easily implement commands with complex options.
- The implemented commands can be called from the CLI / RESTAPI / Web / Edge screen.
- The implemented commands can be executed on a remote server via redis.

# Install
- Install cmdbox with the following command.
- Also install the docker version of the redis server.
```bash
docker run -p 6379:6379 --name redis -e REDIS_PASSWORD=password -it ubuntu/redis:latest
pip install cmdbox
cmdbox -v
```
- When using SAML in web mode, install the modules with dependencies.
```bash
pip install xmlsec==1.3.13 python3-saml
apt-get install -y pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl build-essential libopencv-dev
```
- When using `--agent use` in web mode, install the modules with dependencies.
```bash
pip install google-adk litellm fastmcp
```
# Run
- Run the cmdbox server.
```bash
cmdbox -m server -c start &
```
- Run the cmdbox web.
```bash
cmdbox -m web -c start --signin_file .cmdbox/user_list.yml &
```
- Run the cmdbox web with agent.
- Below is an example of using Google vertexai.
- Other available options include Azure OpenAI and Ollama.
```bash
cmdbox -m web -c start --signin_file .cmdbox/user_list.yml --agent use --llmprov vertexai --llmmodel gemini-2.0-flash --llmlocation us-central1 --llmsvaccountfile <account json file>
```
# Tutorial
- Open the ```.sample/sample_project``` folder in the current directory with VSCode.

- Install dependent libraries.
```bash
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
```
- Run the project.

- The localhost web screen will open.

- Enter ```user01 / user01``` for the initial ID and PW to sign in.
- Using this web screen, you can easily execute the commands implemented in cmdbox.

- Let's look at the command to get a list of files as an example.
- Press the plus button under Commands to open the Add dialog.
- Then enter the following.

- Press the ```Save``` button once and then press the ```Execute``` button.
- The results of the command execution are displayed.

- Open the saved ```client_time``` and press the ```Raw``` button.
- You will see how to execute the same command on the command line; the RESTAPI URL is also displayed.

## How to implement a new command using cmdbox
- Under the ```sample/app/features/cli``` folder, you will find an implementation of the ```sample_client_time``` mentioned earlier.
- The implementation is as follows. (Slightly abbreviated display)
- Create the following code and save it in the ```sample/app/features/cli``` folder.
```python
from cmdbox.app import common, feature
from typing import Dict, Any, Tuple, Union, List
import argparse
import datetime
import logging
class ClientTime(feature.Feature):
def get_mode(self) -> Union[str, List[str]]:
return "client"
def get_cmd(self):
return 'time'
def get_option(self):
return dict(
type=Options.T_STR, default=None, required=False, multi=False, hide=False, use_redis=self.USE_REDIS_FALSE,
description_ja="クライアント側の現在時刻を表示します。",
description_en="Displays the current time at the client side.",
choice=[
dict(opt="timedelta", type=Options.T_INT, default=9, required=False, multi=False, hide=False, choice=None,
description_ja="時差の時間数を指定します。",
description_en="Specify the number of hours of time difference."),
])
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
tz = datetime.timezone(datetime.timedelta(hours=args.timedelta))
dt = datetime.datetime.now(tz)
ret = dict(success=dict(data=dt.strftime('%Y-%m-%d %H:%M:%S')))
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
if 'success' not in ret:
return 1, ret, None
return 0, ret, None
def edgerun(self, opt, tool, logger, timeout, prevres = None):
status, res = tool.exec_cmd(opt, logger, timeout, prevres)
tool.notify(res)
yield 1, res
```
- If you want to implement server-side processing, please refer to ```sample_server_time```.
```python
from cmdbox.app import common, client, feature
from cmdbox.app.commons import redis_client
from cmdbox.app.options import Options
from pathlib import Path
from typing import Dict, Any, Tuple, Union, List
import argparse
import datetime
import logging
class ServerTime(feature.Feature):
def get_mode(self) -> Union[str, List[str]]:
return "server"
def get_cmd(self):
return 'time'
def get_option(self):
return dict(
type=Options.T_STR, default=None, required=False, multi=False, hide=False, use_redis=self.USE_REDIS_FALSE,
description_ja="サーバー側の現在時刻を表示します。",
description_en="Displays the current time at the server side.",
choice=[
dict(opt="host", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None,
description_ja="Redisサーバーのサービスホストを指定します。",
description_en="Specify the service host of the Redis server."),
dict(opt="port", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None,
description_ja="Redisサーバーのサービスポートを指定します。",
description_en="Specify the service port of the Redis server."),
dict(opt="password", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None,
description_ja="Redisサーバーのアクセスパスワード(任意)を指定します。省略時は `password` を使用します。",
description_en="Specify the access password of the Redis server (optional). If omitted, `password` is used."),
dict(opt="svname", type=Options.T_STR, default=self.default_svname, required=True, multi=False, hide=True, choice=None,
description_ja="サーバーのサービス名を指定します。省略時は `server` を使用します。",
description_en="Specify the service name of the inference server. If omitted, `server` is used."),
dict(opt="timedelta", type=Options.T_INT, default=9, required=False, multi=False, hide=False, choice=None,
description_ja="時差の時間数を指定します。",
description_en="Specify the number of hours of time difference."),
dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,
description_ja="Redisサーバーへの再接続回数を指定します。0以下を指定すると永遠に再接続を行います。",
description_en="Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever."),
dict(opt="retry_interval", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,
description_ja="Redisサーバーに再接続までの秒数を指定します。",
description_en="Specifies the number of seconds before reconnecting to the Redis server."),
dict(opt="timeout", type=Options.T_INT, default="15", required=False, multi=False, hide=True, choice=None,
description_ja="サーバーの応答が返ってくるまでの最大待ち時間を指定。",
description_en="Specify the maximum waiting time until the server responds."),
])
def get_svcmd(self):
return 'server_time'
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
ret = cl.redis_cli.send_cmd(self.get_svcmd(), [str(args.timedelta)],
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout)
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
if 'success' not in ret:
return 1, ret, None
return 0, ret, None
def is_cluster_redirect(self):
return False
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
sessions:Dict[str, Dict[str, Any]]) -> int:
td = 9 if msg[2] == None else int(msg[2])
tz = datetime.timezone(datetime.timedelta(hours=td))
dt = datetime.datetime.now(tz)
ret = dict(success=dict(data=dt.strftime('%Y-%m-%d %H:%M:%S')))
redis_cli.rpush(msg[1], ret)
return self.RESP_SCCESS
def edgerun(self, opt, tool, logger, timeout, prevres = None):
status, res = tool.exec_cmd(opt, logger, timeout, prevres)
tool.notify(res)
yield 1, res
```
- Open the file ```sample/extensions/features.yml```. The file should look something like this.
- This file specifies where new commands are to be read.
- For example, if you want to add a package to read, add a new ```package``` and ```prefix``` to ```features.cli```.
- Note that ```features.web``` can be used to add a new web screen.
- If you only want to call commands added in ```features.cli``` via RESTAPI, no additional implementation is needed in ```features.web```.
```yml
features:
cli: # Specify a list of package names in which the module implementing the command is located.
- package: cmdbox.app.features.cli # Package Name. Classes inheriting from cmdbox.app.feature.Feature.
prefix: cmdbox_ # Module name prefix. Modules that begin with this letter are eligible.
exclude_modules: [] # Specify the module name to exclude from the list of modules to be loaded.
web: # Specify a list of package names with modules that implement web screens and RESTAPIs.
- package: cmdbox.app.features.web # Package Name. Classes inheriting from cmdbox.app.feature.WebFeature .
prefix: cmdbox_web_ # Module name prefix. Modules that begin with this letter are eligible.
args: # Specifies default or forced arguments for the specified command.
cli: # Specify rules to apply default values or force arguments.
- rule: # Specify the rules for applying default values and forced arguments for each command line option.
# e.g. mode: web
default: # Specify a default value for each item to be set when a rule is matched.
# e.g. doc_root: f"{Path(self.ver.__file__).parent / 'web'}"
coercion: # Specify a coercion value for each item to be set when a rule is matched.
# e.g. doc_root: f"{Path(self.ver.__file__).parent / 'web'}"
aliases: # Specify the alias for the specified command.
cli: # Specify the alias for the command line.
- source: # Specifies the command from which the alias originates.
mode: # Specify the mode of the source command. The exact match "mode" is selected.
# e.g. client
cmd: # Specify the source command to be aliased. The regex match "cmd" is selected.
# e.g. (.+)_(.+)
target: # Specifies the command to be aliased to.
mode: # Specify the mode of the target command. Create an alias for this “mode”.
# e.g. CLIENT
cmd: # Specify the target command to be aliased. Create an alias for this “cmd”, referring to the regular expression group of source by "{n}".
# e.g. {2}_{1}
move: # Specify whether to move the regular expression group of the source to the target.
# e.g. true
web: # Specify the alias for the RESTAPI.
- source: # Specifies the RESTAPI from which the alias originates.
path: # Specify the path of the source RESTAPI. The regex match "path" is selected.
# e.g. /exec_(.+)
target: # Specifies the RESTAPI to be aliased to.
path: # Specify the path of the target RESTAPI. Create an alias for this “path”, referring to the regular expression group of source by "{n}".
# e.g. /{1}_exec
move: # Specify whether to move the regular expression group of the source to the target.
# e.g. true
agentrule: # Specifies a list of rules that determine which commands the agent can execute.
policy: deny # Specify the default policy for the rule. The value can be allow or deny.
rules: # Specify the rules for the commands that the agent can execute according to the group to which the user belongs.
- mode: audit # Specify the "mode" as the condition for applying the rule.
cmds: [search, write] # Specify the "cmd" to which the rule applies. Multiple items can be specified in a list.
rule: allow # Specifies whether the specified command is allowed or not. Values are allow or deny.
- mode: client
cmds: [file_copy, file_download, file_list, file_mkdir, file_move, file_remove, file_rmdir, file_upload, server_info]
rule: allow
- mode: cmd
cmds: [list, load]
rule: allow
- mode: server
cmds: [list]
rule: allow
- mode: web
cmds: [gencert, genpass, group_list, user_list]
rule: allow
audit:
enabled: true # Specify whether to enable the audit function.
write:
mode: audit # Specify the mode of the feature to be writed.
cmd: write # Specify the command to be writed.
search:
mode: audit # Specify the mode of the feature to be searched.
cmd: search # Specify the command to be searched.
options: # Specify the options for the audit function.
host: localhost # Specify the service host of the audit Redis server.However, if it is specified as a command line argument, it is ignored.
port: 6379 # Specify the service port of the audit Redis server.However, if it is specified as a command line argument, it is ignored.
password: password # Specify the access password of the audit Redis server.However, if it is specified as a command line argument, it is ignored.
svname: cmdbox # Specify the audit service name of the inference server.However, if it is specified as a command line argument, it is ignored.
retry_count: 3 # Specifies the number of reconnections to the audit Redis server.If less than 0 is specified, reconnection is forever.
retry_interval: 1 # Specifies the number of seconds before reconnecting to the audit Redis server.
timeout: 15 # Specify the maximum waiting time until the server responds.
pg_enabled: False # Specify True if using the postgresql database server.
pg_host: localhost # Specify the postgresql host.
pg_port: 5432 # Specify the postgresql port.
pg_user: postgres # Specify the postgresql user name.
pg_password: password # Specify the postgresql password.
pg_dbname: audit # Specify the postgresql database name.
retention_period_days: 365 # Specify the number of days to retain audit logs.
```
- The following files should also be known when using commands on the web screen or RESTAPI.
- Open the file ```sample/extensions/user_list.yml```. The file should look something like this.
- This file manages the users and groups that are allowed Web access and their rules.
- The rule of the previous command is ```allow``` for users in the ```user``` group in ```cmdrule.rules```.
```yml
users: # A list of users, each of which is a map that contains the following fields.
- uid: 1 # An ID that identifies a user. No two users can have the same ID.
name: admin # A name that identifies the user. No two users can have the same name.
password: XXXXX # The user's password. The value is hashed with the hash function specified in the next hash field.
hash: plain # The hash function used to hash the password, which can be plain, md5, sha1, or sha256, or oauth2, or saml.
groups: [admin] # A list of groups to which the user belongs, as specified in the groups field.
email: admin@aaa.bbb.jp # The email address of the user, used when authenticating using the provider specified in the oauth2 or saml field.
- uid: 101
name: user01
password: XXXXX
hash: md5
groups: [user]
email: user01@aaa.bbb.jp
- uid: 102
name: user02
password: XXXXX
hash: sha1
groups: [readonly]
email: user02@aaa.bbb.jp
- uid: 103
name: user03
password: XXXXX
hash: sha256
groups: [editor]
email: user03@aaa.bbb.jp
groups: # A list of groups, each of which is a map that contains the following fields.
- gid: 1 # An ID that identifies a group. No two groups can have the same ID.
name: admin # A name that identifies the group. No two groups can have the same name.
- gid: 2
name: guest
- gid: 101
name: user
- gid: 102
name: readonly
parent: user # The parent group of the group. If the parent group is not specified, the group is a top-level group.
- gid: 103
name: editor
parent: user
cmdrule: # A list of command rules, Specify a rule that determines whether or not a command is executable when executed by a user in web mode.
policy: deny # Specify the default policy for the rule. The value can be allow or deny.
rules: # Specify rules to allow or deny execution of the command, depending on the group the user belongs to.
- groups: [admin]
rule: allow
- groups: [user] # Specify the groups to which the rule applies.
mode: client # Specify the "mode" as the condition for applying the rule.
cmds: [file_download, file_list, server_info] # Specify the "cmd" to which the rule applies. Multiple items can be specified in a list.
rule: allow # Specifies whether or not the specified command is allowed for the specified group. The value can be allow or deny.
- groups: [user]
mode: server
cmds: [list]
rule: allow
- groups: [user]
mode: cmd
cmds: [list, load]
rule: allow
- groups: [user, guest]
mode: audit
cmds: [write]
rule: allow
- groups: [user, guest]
mode: web
cmds: [genpass]
rule: allow
- groups: [editor]
mode: client
cmds: [file_copy, file_mkdir, file_move, file_remove, file_rmdir, file_upload]
rule: allow
pathrule: # List of RESTAPI rules, rules that determine whether or not a RESTAPI can be executed when a user in web mode accesses it.
policy: deny # Specify the default policy for the rule. The value can be allow or deny.
rules: # Specify rules to allow or deny execution of the RESTAPI, depending on the group the user belongs to.
- groups: [admin] # Specify the groups to which the rule applies.
paths: [/] # Specify the "path" to which the rule applies. Multiple items can be specified in a list.
rule: allow # Specifies whether or not the specified RESTAPI is allowed for the specified group. The value can be allow or deny.
- groups: [guest]
paths: [/signin, /assets, /copyright, /dosignin, /dosignout, /password/change,
/gui, /get_server_opt, /usesignout, /versions_cmdbox, /versions_used]
rule: allow
- groups: [user]
paths: [/signin, /assets, /bbforce_cmd, /copyright, /dosignin, /dosignout, /password/change,
/gui/user_data/load, /gui/user_data/save, /gui/user_data/delete,
/agent, /mcpsv,
/exec_cmd, /exec_pipe, /filer, /result, /gui, /get_server_opt, /usesignout, /versions_cmdbox, /versions_used]
rule: allow
- groups: [readonly]
paths: [/gui/del_cmd, /gui/del_pipe, /gui/save_cmd, /gui/save_pipe]
rule: deny
- groups: [editor]
paths: [/gui/del_cmd, /gui/del_pipe, /gui/save_cmd, /gui/save_pipe]
rule: allow
password: # Password settings.
policy: # Password policy settings.
enabled: true # Specify whether or not to enable password policy.
not_same_before: true # Specify whether or not to allow the same password as the previous one.
min_length: 16 # Specify the minimum length of the password.
max_length: 64 # Specify the maximum length of the password.
min_lowercase: 1 # Specify the minimum number of lowercase letters in the password.
min_uppercase: 1 # Specify the minimum number of uppercase letters in the password.
min_digit: 1 # Specify the minimum number of digits in the password.
min_symbol: 1 # Specify the minimum number of symbol characters in the password.
not_contain_username: true # Specify whether or not to include the username in the password.
expiration: # Password expiration settings.
enabled: true # Specify whether or not to enable password expiration.
period: 90 # Specify the number of days after which the password will expire.
notify: 7 # Specify the number of days before the password expires that a notification will be sent.
lockout: # Account lockout settings.
enabled: true # Specify whether or not to enable account lockout.
threshold: 5 # Specify the number of failed login attempts before the account is locked.
reset: 30 # Specify the number of minutes after which the failed login count will be reset.
apikey:
gen_cert: # Specify whether to generate a certificate for API key.
enabled: true # Specify whether to enable certificate generation for API key.
privatekey: idp_private.pem # Specify the destination file for the generated private key.
certificate: idp_cert.pem # Specify the destination file for the generated certificate.
publickey: idp_public.pem # Specify the destination file for the generated public key.
gen_jwt: # Specify whether to generate JWT for API key.
enabled: true # Specify whether to enable JWT generation for API key.
privatekey: idp_private.pem # Specify the private key file for JWT generation.
privatekey_passphrase: # Specify the passphrase for the private key file.
# If the private key is encrypted, specify the passphrase here.
algorithm: RS256 # Specify the algorithm used to generate the JWT. The value can be RS256, PS256, or ES256.
claims: # Specify the claims to be included in the JWT.
iss: identity_provider # Specify the issuer of the JWT. This is usually the name of the identity provider.
sub: app_user # Specify the subject of the JWT. This is usually the name of the application.
aud: app_organization # Specify the audience of the JWT. This is usually the name of the organization that will use the application.
exp: 31536000 # Specify the expiration time of the JWT in seconds. The default is 31536000 seconds (1 year).
verify_jwt: # Specify whether to verify JWT for API key.
enabled: true # Specify whether to enable JWT verification for API key.
certificate: idp_cert.pem # Specify the certificate file for JWT verification.
publickey: idp_public.pem # Specify the public key file for JWT verification. Not required if certificate exists.
issuer: identity_provider # Specify the issuer of the JWT. This is usually the name of the identity provider. (If not specified, no verification)
audience: app_organization # Specify the audience of the JWT. This is usually the name of the organization that will use the application. (If not specified, no verification)
algorithm: RS256 # Specify the algorithm used to verify the JWT. The value can be RS256, PS256, or ES256.
oauth2: # OAuth2 settings.
providers: # This is a per-provider setting for OAuth2.
google: # Google's OAuth2 configuration.
enabled: false # Specify whether to enable Google's OAuth2.
client_id: XXXXXXXXXXX # Specify Google's OAuth2 client ID.
client_secret: XXXXXXXXXXX # Specify Google's OAuth2 client secret.
redirect_uri: https://localhost:8443/oauth2/google/callback # Specify Google's OAuth2 redirect URI.
scope: ['email'] # Specify the scope you want to retrieve with Google's OAuth2. Usually, just reading the email is sufficient.
signin_module: # Specify the module name that implements the sign-in.
cmdbox.app.auth.google_signin
note: # Specify a description such as Google's OAuth2 reference site.
- https://developers.google.com/identity/protocols/oauth2/web-server?hl=ja#httprest
github: # OAuth2 settings for GitHub.
enabled: false # Specify whether to enable OAuth2 for GitHub.
client_id: XXXXXXXXXXX # Specify the OAuth2 client ID for GitHub.
client_secret: XXXXXXXXXXX # Specify the GitHub OAuth2 client secret.
redirect_uri: https://localhost:8443/oauth2/github/callback # Specify the OAuth2 redirect URI for GitHub.
scope: ['user:email'] # Specify the scope you want to get from GitHub's OAuth2. Usually, just reading the email is sufficient.
signin_module: # Specify the module name that implements the sign-in.
cmdbox.app.auth.github_signin
note: # Specify a description, such as a reference site for OAuth2 on GitHub.
- https://docs.github.com/ja/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#scopes
azure: # OAuth2 settings for Azure AD.
enabled: false # Specify whether to enable OAuth2 for Azure AD.
tenant_id: XXXXXXXXXXX # Specify the tenant ID for Azure AD.
client_id: XXXXXXXXXXX # Specify the OAuth2 client ID for Azure AD.
client_secret: XXXXXXXXXXX # Specify the Azure AD OAuth2 client secret.
redirect_uri: https://localhost:8443/oauth2/azure/callback # Specify the OAuth2 redirect URI for Azure AD.
scope: ['openid', 'profile', 'email', 'https://graph.microsoft.com/mail.read']
signin_module: # Specify the module name that implements the sign-in.
cmdbox.app.auth.azure_signin
note: # Specify a description, such as a reference site for Azure AD's OAuth2.
- https://learn.microsoft.com/ja-jp/entra/identity-platform/v2-oauth2-auth-code-flow
saml: # SAML settings.
providers: # This is a per-provider setting for OAuth2.
azure: # SAML settings for Azure AD.
enabled: false # Specify whether to enable SAML authentication for Azure AD.
signin_module: # Specify the module name that implements the sign-in.
cmdbox.app.auth.azure_signin_saml # Specify the python3-saml configuration.
# see) https://github.com/SAML-Toolkits/python3-saml
sp:
entityId: https://localhost:8443/
assertionConsumerService:
url: https://localhost:8443/saml/azure/callback
binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
attributeConsumingService: {}
singleLogoutService:
binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
NameIDFormat: urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
x509cert: ''
privateKey: ''
idp:
entityId: https://sts.windows.net/{tenant-id}/
singleSignOnService:
url: https://login.microsoftonline.com/{tenant-id}/saml2
binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
x509cert: XXXXXXXXXXX
singleLogoutService: {}
certFingerprint: ''
certFingerprintAlgorithm: sha1
```
- See the documentation for references to each file.
- Documentation is [here](https://hamacom2004jp.github.io/cmdbox/).
# Lisence
This project is licensed under the MIT License, see the LICENSE file for details
Raw data
{
"_id": null,
"home_page": "https://github.com/hamacom2004jp/cmdbox",
"name": "cmdbox",
"maintainer": "hamacom2004jp",
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "hamacom2004jp@gmail.com",
"keywords": "cli restapi redis fastapi",
"author": "hamacom2004jp",
"author_email": "hamacom2004jp@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/f7/51/f52bea7c2d055062b511e34999ab9ff170211353f6f525348c0e4ad1400d/cmdbox-0.6.2.3.tar.gz",
"platform": null,
"description": "# cmdbox (Command Development Application)\r\n\r\n- It is a command development application with a plugin mechanism.\r\n- Documentation is [here](https://hamacom2004jp.github.io/cmdbox/).\r\n- With cmdbox, you can easily implement commands with complex options.\r\n- The implemented commands can be called from the CLI / RESTAPI / Web / Edge screen.\r\n- The implemented commands can be executed on a remote server via redis.\r\n\r\n\r\n\r\n# Install\r\n\r\n- Install cmdbox with the following command.\r\n- Also install the docker version of the redis server.\r\n\r\n```bash\r\ndocker run -p 6379:6379 --name redis -e REDIS_PASSWORD=password -it ubuntu/redis:latest\r\npip install cmdbox\r\ncmdbox -v\r\n```\r\n\r\n- When using SAML in web mode, install the modules with dependencies.\r\n```bash\r\npip install xmlsec==1.3.13 python3-saml\r\napt-get install -y pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl build-essential libopencv-dev\r\n```\r\n\r\n- When using `--agent use` in web mode, install the modules with dependencies.\r\n```bash\r\npip install google-adk litellm fastmcp\r\n```\r\n\r\n# Run\r\n\r\n- Run the cmdbox server.\r\n\r\n```bash\r\ncmdbox -m server -c start &\r\n```\r\n\r\n- Run the cmdbox web.\r\n\r\n```bash\r\ncmdbox -m web -c start --signin_file .cmdbox/user_list.yml &\r\n```\r\n\r\n- Run the cmdbox web with agent.\r\n- Below is an example of using Google vertexai.\r\n- Other available options include Azure OpenAI and Ollama.\r\n\r\n```bash\r\ncmdbox -m web -c start --signin_file .cmdbox/user_list.yml --agent use --llmprov vertexai --llmmodel gemini-2.0-flash --llmlocation us-central1 --llmsvaccountfile <account json file>\r\n```\r\n\r\n\r\n# Tutorial\r\n\r\n- Open the ```.sample/sample_project``` folder in the current directory with VSCode.\r\n\r\n\r\n\r\n- Install dependent libraries.\r\n\r\n```bash\r\npython -m venv .venv\r\n. .venv/bin/activate\r\npip install -r requirements.txt\r\n```\r\n\r\n- Run the project.\r\n\r\n\r\n\r\n- The localhost web screen will open.\r\n\r\n\r\n\r\n- Enter ```user01 / user01``` for the initial ID and PW to sign in.\r\n- Using this web screen, you can easily execute the commands implemented in cmdbox.\r\n\r\n\r\n\r\n- Let's look at the command to get a list of files as an example.\r\n- Press the plus button under Commands to open the Add dialog.\r\n- Then enter the following.\r\n\r\n\r\n\r\n- Press the ```Save``` button once and then press the ```Execute``` button.\r\n- The results of the command execution are displayed.\r\n\r\n\r\n\r\n- Open the saved ```client_time``` and press the ```Raw``` button.\r\n- You will see how to execute the same command on the command line; the RESTAPI URL is also displayed.\r\n\r\n\r\n\r\n\r\n## How to implement a new command using cmdbox\r\n\r\n- Under the ```sample/app/features/cli``` folder, you will find an implementation of the ```sample_client_time``` mentioned earlier.\r\n- The implementation is as follows. (Slightly abbreviated display)\r\n- Create the following code and save it in the ```sample/app/features/cli``` folder.\r\n\r\n```python\r\nfrom cmdbox.app import common, feature\r\nfrom typing import Dict, Any, Tuple, Union, List\r\nimport argparse\r\nimport datetime\r\nimport logging\r\n\r\n\r\nclass ClientTime(feature.Feature):\r\n def get_mode(self) -> Union[str, List[str]]:\r\n return \"client\"\r\n\r\n def get_cmd(self):\r\n return 'time'\r\n\r\n def get_option(self):\r\n return dict(\r\n type=Options.T_STR, default=None, required=False, multi=False, hide=False, use_redis=self.USE_REDIS_FALSE,\r\n description_ja=\"\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5074\u306e\u73fe\u5728\u6642\u523b\u3092\u8868\u793a\u3057\u307e\u3059\u3002\",\r\n description_en=\"Displays the current time at the client side.\",\r\n choice=[\r\n dict(opt=\"timedelta\", type=Options.T_INT, default=9, required=False, multi=False, hide=False, choice=None,\r\n description_ja=\"\u6642\u5dee\u306e\u6642\u9593\u6570\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\",\r\n description_en=\"Specify the number of hours of time difference.\"),\r\n ])\r\n\r\n def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:\r\n tz = datetime.timezone(datetime.timedelta(hours=args.timedelta))\r\n dt = datetime.datetime.now(tz)\r\n ret = dict(success=dict(data=dt.strftime('%Y-%m-%d %H:%M:%S')))\r\n common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)\r\n if 'success' not in ret:\r\n return 1, ret, None\r\n return 0, ret, None\r\n\r\n def edgerun(self, opt, tool, logger, timeout, prevres = None):\r\n status, res = tool.exec_cmd(opt, logger, timeout, prevres)\r\n tool.notify(res)\r\n yield 1, res\r\n```\r\n\r\n- If you want to implement server-side processing, please refer to ```sample_server_time```.\r\n\r\n```python\r\nfrom cmdbox.app import common, client, feature\r\nfrom cmdbox.app.commons import redis_client\r\nfrom cmdbox.app.options import Options\r\nfrom pathlib import Path\r\nfrom typing import Dict, Any, Tuple, Union, List\r\nimport argparse\r\nimport datetime\r\nimport logging\r\n\r\n\r\nclass ServerTime(feature.Feature):\r\n def get_mode(self) -> Union[str, List[str]]:\r\n return \"server\"\r\n\r\n def get_cmd(self):\r\n return 'time'\r\n\r\n def get_option(self):\r\n return dict(\r\n type=Options.T_STR, default=None, required=False, multi=False, hide=False, use_redis=self.USE_REDIS_FALSE,\r\n description_ja=\"\u30b5\u30fc\u30d0\u30fc\u5074\u306e\u73fe\u5728\u6642\u523b\u3092\u8868\u793a\u3057\u307e\u3059\u3002\",\r\n description_en=\"Displays the current time at the server side.\",\r\n choice=[\r\n dict(opt=\"host\", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None,\r\n description_ja=\"Redis\u30b5\u30fc\u30d0\u30fc\u306e\u30b5\u30fc\u30d3\u30b9\u30db\u30b9\u30c8\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\",\r\n description_en=\"Specify the service host of the Redis server.\"),\r\n dict(opt=\"port\", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None,\r\n description_ja=\"Redis\u30b5\u30fc\u30d0\u30fc\u306e\u30b5\u30fc\u30d3\u30b9\u30dd\u30fc\u30c8\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\",\r\n description_en=\"Specify the service port of the Redis server.\"),\r\n dict(opt=\"password\", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None,\r\n description_ja=\"Redis\u30b5\u30fc\u30d0\u30fc\u306e\u30a2\u30af\u30bb\u30b9\u30d1\u30b9\u30ef\u30fc\u30c9(\u4efb\u610f)\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\u7701\u7565\u6642\u306f `password` \u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\",\r\n description_en=\"Specify the access password of the Redis server (optional). If omitted, `password` is used.\"),\r\n dict(opt=\"svname\", type=Options.T_STR, default=self.default_svname, required=True, multi=False, hide=True, choice=None,\r\n description_ja=\"\u30b5\u30fc\u30d0\u30fc\u306e\u30b5\u30fc\u30d3\u30b9\u540d\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\u7701\u7565\u6642\u306f `server` \u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\",\r\n description_en=\"Specify the service name of the inference server. If omitted, `server` is used.\"),\r\n dict(opt=\"timedelta\", type=Options.T_INT, default=9, required=False, multi=False, hide=False, choice=None,\r\n description_ja=\"\u6642\u5dee\u306e\u6642\u9593\u6570\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\",\r\n description_en=\"Specify the number of hours of time difference.\"),\r\n dict(opt=\"retry_count\", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,\r\n description_ja=\"Redis\u30b5\u30fc\u30d0\u30fc\u3078\u306e\u518d\u63a5\u7d9a\u56de\u6570\u3092\u6307\u5b9a\u3057\u307e\u3059\u30020\u4ee5\u4e0b\u3092\u6307\u5b9a\u3059\u308b\u3068\u6c38\u9060\u306b\u518d\u63a5\u7d9a\u3092\u884c\u3044\u307e\u3059\u3002\",\r\n description_en=\"Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever.\"),\r\n dict(opt=\"retry_interval\", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,\r\n description_ja=\"Redis\u30b5\u30fc\u30d0\u30fc\u306b\u518d\u63a5\u7d9a\u307e\u3067\u306e\u79d2\u6570\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\",\r\n description_en=\"Specifies the number of seconds before reconnecting to the Redis server.\"),\r\n dict(opt=\"timeout\", type=Options.T_INT, default=\"15\", required=False, multi=False, hide=True, choice=None,\r\n description_ja=\"\u30b5\u30fc\u30d0\u30fc\u306e\u5fdc\u7b54\u304c\u8fd4\u3063\u3066\u304f\u308b\u307e\u3067\u306e\u6700\u5927\u5f85\u3061\u6642\u9593\u3092\u6307\u5b9a\u3002\",\r\n description_en=\"Specify the maximum waiting time until the server responds.\"),\r\n ])\r\n\r\n def get_svcmd(self):\r\n return 'server_time'\r\n\r\n def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:\r\n cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)\r\n ret = cl.redis_cli.send_cmd(self.get_svcmd(), [str(args.timedelta)],\r\n retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout)\r\n common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)\r\n if 'success' not in ret:\r\n return 1, ret, None\r\n return 0, ret, None\r\n\r\n def is_cluster_redirect(self):\r\n return False\r\n\r\n def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],\r\n sessions:Dict[str, Dict[str, Any]]) -> int:\r\n td = 9 if msg[2] == None else int(msg[2])\r\n tz = datetime.timezone(datetime.timedelta(hours=td))\r\n dt = datetime.datetime.now(tz)\r\n ret = dict(success=dict(data=dt.strftime('%Y-%m-%d %H:%M:%S')))\r\n redis_cli.rpush(msg[1], ret)\r\n return self.RESP_SCCESS\r\n\r\n def edgerun(self, opt, tool, logger, timeout, prevres = None):\r\n status, res = tool.exec_cmd(opt, logger, timeout, prevres)\r\n tool.notify(res)\r\n yield 1, res\r\n```\r\n\r\n- Open the file ```sample/extensions/features.yml```. The file should look something like this.\r\n- This file specifies where new commands are to be read.\r\n- For example, if you want to add a package to read, add a new ```package``` and ```prefix``` to ```features.cli```.\r\n- Note that ```features.web``` can be used to add a new web screen.\r\n- If you only want to call commands added in ```features.cli``` via RESTAPI, no additional implementation is needed in ```features.web```.\r\n\r\n\r\n```yml\r\nfeatures:\r\n cli: # Specify a list of package names in which the module implementing the command is located.\r\n - package: cmdbox.app.features.cli # Package Name. Classes inheriting from cmdbox.app.feature.Feature.\r\n prefix: cmdbox_ # Module name prefix. Modules that begin with this letter are eligible.\r\n exclude_modules: [] # Specify the module name to exclude from the list of modules to be loaded.\r\n web: # Specify a list of package names with modules that implement web screens and RESTAPIs.\r\n - package: cmdbox.app.features.web # Package Name. Classes inheriting from cmdbox.app.feature.WebFeature .\r\n prefix: cmdbox_web_ # Module name prefix. Modules that begin with this letter are eligible.\r\nargs: # Specifies default or forced arguments for the specified command.\r\n cli: # Specify rules to apply default values or force arguments.\r\n - rule: # Specify the rules for applying default values and forced arguments for each command line option.\r\n # e.g. mode: web\r\n default: # Specify a default value for each item to be set when a rule is matched.\r\n # e.g. doc_root: f\"{Path(self.ver.__file__).parent / 'web'}\"\r\n coercion: # Specify a coercion value for each item to be set when a rule is matched.\r\n # e.g. doc_root: f\"{Path(self.ver.__file__).parent / 'web'}\"\r\naliases: # Specify the alias for the specified command.\r\n cli: # Specify the alias for the command line.\r\n - source: # Specifies the command from which the alias originates.\r\n mode: # Specify the mode of the source command. The exact match \"mode\" is selected.\r\n # e.g. client\r\n cmd: # Specify the source command to be aliased. The regex match \"cmd\" is selected.\r\n # e.g. (.+)_(.+)\r\n target: # Specifies the command to be aliased to.\r\n mode: # Specify the mode of the target command. Create an alias for this \u201cmode\u201d.\r\n # e.g. CLIENT\r\n cmd: # Specify the target command to be aliased. Create an alias for this \u201ccmd\u201d, referring to the regular expression group of source by \"{n}\".\r\n # e.g. {2}_{1}\r\n move: # Specify whether to move the regular expression group of the source to the target.\r\n # e.g. true\r\n web: # Specify the alias for the RESTAPI.\r\n - source: # Specifies the RESTAPI from which the alias originates.\r\n path: # Specify the path of the source RESTAPI. The regex match \"path\" is selected.\r\n # e.g. /exec_(.+)\r\n target: # Specifies the RESTAPI to be aliased to.\r\n path: # Specify the path of the target RESTAPI. Create an alias for this \u201cpath\u201d, referring to the regular expression group of source by \"{n}\".\r\n # e.g. /{1}_exec\r\n move: # Specify whether to move the regular expression group of the source to the target.\r\n # e.g. true\r\nagentrule: # Specifies a list of rules that determine which commands the agent can execute.\r\n policy: deny # Specify the default policy for the rule. The value can be allow or deny.\r\n rules: # Specify the rules for the commands that the agent can execute according to the group to which the user belongs.\r\n - mode: audit # Specify the \"mode\" as the condition for applying the rule.\r\n cmds: [search, write] # Specify the \"cmd\" to which the rule applies. Multiple items can be specified in a list.\r\n rule: allow # Specifies whether the specified command is allowed or not. Values are allow or deny.\r\n - mode: client\r\n cmds: [file_copy, file_download, file_list, file_mkdir, file_move, file_remove, file_rmdir, file_upload, server_info]\r\n rule: allow\r\n - mode: cmd\r\n cmds: [list, load]\r\n rule: allow\r\n - mode: server\r\n cmds: [list]\r\n rule: allow\r\n - mode: web\r\n cmds: [gencert, genpass, group_list, user_list]\r\n rule: allow\r\naudit:\r\n enabled: true # Specify whether to enable the audit function.\r\n write:\r\n mode: audit # Specify the mode of the feature to be writed.\r\n cmd: write # Specify the command to be writed.\r\n search:\r\n mode: audit # Specify the mode of the feature to be searched.\r\n cmd: search # Specify the command to be searched.\r\n options: # Specify the options for the audit function.\r\n host: localhost # Specify the service host of the audit Redis server.However, if it is specified as a command line argument, it is ignored.\r\n port: 6379 # Specify the service port of the audit Redis server.However, if it is specified as a command line argument, it is ignored.\r\n password: password # Specify the access password of the audit Redis server.However, if it is specified as a command line argument, it is ignored.\r\n svname: cmdbox # Specify the audit service name of the inference server.However, if it is specified as a command line argument, it is ignored.\r\n retry_count: 3 # Specifies the number of reconnections to the audit Redis server.If less than 0 is specified, reconnection is forever.\r\n retry_interval: 1 # Specifies the number of seconds before reconnecting to the audit Redis server.\r\n timeout: 15 # Specify the maximum waiting time until the server responds.\r\n pg_enabled: False # Specify True if using the postgresql database server.\r\n pg_host: localhost # Specify the postgresql host.\r\n pg_port: 5432 # Specify the postgresql port.\r\n pg_user: postgres # Specify the postgresql user name.\r\n pg_password: password # Specify the postgresql password.\r\n pg_dbname: audit # Specify the postgresql database name.\r\n retention_period_days: 365 # Specify the number of days to retain audit logs.\r\n\r\n```\r\n\r\n- The following files should also be known when using commands on the web screen or RESTAPI.\r\n- Open the file ```sample/extensions/user_list.yml```. The file should look something like this.\r\n- This file manages the users and groups that are allowed Web access and their rules.\r\n- The rule of the previous command is ```allow``` for users in the ```user``` group in ```cmdrule.rules```.\r\n\r\n\r\n```yml\r\nusers: # A list of users, each of which is a map that contains the following fields.\r\n- uid: 1 # An ID that identifies a user. No two users can have the same ID.\r\n name: admin # A name that identifies the user. No two users can have the same name.\r\n password: XXXXX # The user's password. The value is hashed with the hash function specified in the next hash field.\r\n hash: plain # The hash function used to hash the password, which can be plain, md5, sha1, or sha256, or oauth2, or saml.\r\n groups: [admin] # A list of groups to which the user belongs, as specified in the groups field.\r\n email: admin@aaa.bbb.jp # The email address of the user, used when authenticating using the provider specified in the oauth2 or saml field.\r\n- uid: 101\r\n name: user01\r\n password: XXXXX\r\n hash: md5\r\n groups: [user]\r\n email: user01@aaa.bbb.jp\r\n- uid: 102\r\n name: user02\r\n password: XXXXX\r\n hash: sha1\r\n groups: [readonly]\r\n email: user02@aaa.bbb.jp\r\n- uid: 103\r\n name: user03\r\n password: XXXXX\r\n hash: sha256\r\n groups: [editor]\r\n email: user03@aaa.bbb.jp\r\ngroups: # A list of groups, each of which is a map that contains the following fields.\r\n- gid: 1 # An ID that identifies a group. No two groups can have the same ID.\r\n name: admin # A name that identifies the group. No two groups can have the same name.\r\n- gid: 2\r\n name: guest\r\n- gid: 101\r\n name: user\r\n- gid: 102\r\n name: readonly\r\n parent: user # The parent group of the group. If the parent group is not specified, the group is a top-level group.\r\n- gid: 103\r\n name: editor\r\n parent: user\r\ncmdrule: # A list of command rules, Specify a rule that determines whether or not a command is executable when executed by a user in web mode.\r\n policy: deny # Specify the default policy for the rule. The value can be allow or deny.\r\n rules: # Specify rules to allow or deny execution of the command, depending on the group the user belongs to.\r\n - groups: [admin]\r\n rule: allow\r\n - groups: [user] # Specify the groups to which the rule applies.\r\n mode: client # Specify the \"mode\" as the condition for applying the rule.\r\n cmds: [file_download, file_list, server_info] # Specify the \"cmd\" to which the rule applies. Multiple items can be specified in a list.\r\n rule: allow # Specifies whether or not the specified command is allowed for the specified group. The value can be allow or deny.\r\n - groups: [user]\r\n mode: server\r\n cmds: [list]\r\n rule: allow\r\n - groups: [user]\r\n mode: cmd\r\n cmds: [list, load]\r\n rule: allow\r\n - groups: [user, guest]\r\n mode: audit\r\n cmds: [write]\r\n rule: allow\r\n - groups: [user, guest]\r\n mode: web\r\n cmds: [genpass]\r\n rule: allow\r\n - groups: [editor]\r\n mode: client\r\n cmds: [file_copy, file_mkdir, file_move, file_remove, file_rmdir, file_upload]\r\n rule: allow\r\npathrule: # List of RESTAPI rules, rules that determine whether or not a RESTAPI can be executed when a user in web mode accesses it.\r\n policy: deny # Specify the default policy for the rule. The value can be allow or deny.\r\n rules: # Specify rules to allow or deny execution of the RESTAPI, depending on the group the user belongs to.\r\n - groups: [admin] # Specify the groups to which the rule applies.\r\n paths: [/] # Specify the \"path\" to which the rule applies. Multiple items can be specified in a list.\r\n rule: allow # Specifies whether or not the specified RESTAPI is allowed for the specified group. The value can be allow or deny.\r\n - groups: [guest]\r\n paths: [/signin, /assets, /copyright, /dosignin, /dosignout, /password/change,\r\n /gui, /get_server_opt, /usesignout, /versions_cmdbox, /versions_used]\r\n rule: allow\r\n - groups: [user]\r\n paths: [/signin, /assets, /bbforce_cmd, /copyright, /dosignin, /dosignout, /password/change,\r\n /gui/user_data/load, /gui/user_data/save, /gui/user_data/delete,\r\n /agent, /mcpsv,\r\n /exec_cmd, /exec_pipe, /filer, /result, /gui, /get_server_opt, /usesignout, /versions_cmdbox, /versions_used]\r\n rule: allow\r\n - groups: [readonly]\r\n paths: [/gui/del_cmd, /gui/del_pipe, /gui/save_cmd, /gui/save_pipe]\r\n rule: deny\r\n - groups: [editor]\r\n paths: [/gui/del_cmd, /gui/del_pipe, /gui/save_cmd, /gui/save_pipe]\r\n rule: allow\r\npassword: # Password settings.\r\n policy: # Password policy settings.\r\n enabled: true # Specify whether or not to enable password policy.\r\n not_same_before: true # Specify whether or not to allow the same password as the previous one.\r\n min_length: 16 # Specify the minimum length of the password.\r\n max_length: 64 # Specify the maximum length of the password.\r\n min_lowercase: 1 # Specify the minimum number of lowercase letters in the password.\r\n min_uppercase: 1 # Specify the minimum number of uppercase letters in the password.\r\n min_digit: 1 # Specify the minimum number of digits in the password.\r\n min_symbol: 1 # Specify the minimum number of symbol characters in the password.\r\n not_contain_username: true # Specify whether or not to include the username in the password.\r\n expiration: # Password expiration settings.\r\n enabled: true # Specify whether or not to enable password expiration.\r\n period: 90 # Specify the number of days after which the password will expire.\r\n notify: 7 # Specify the number of days before the password expires that a notification will be sent.\r\n lockout: # Account lockout settings.\r\n enabled: true # Specify whether or not to enable account lockout.\r\n threshold: 5 # Specify the number of failed login attempts before the account is locked.\r\n reset: 30 # Specify the number of minutes after which the failed login count will be reset.\r\napikey:\r\n gen_cert: # Specify whether to generate a certificate for API key.\r\n enabled: true # Specify whether to enable certificate generation for API key.\r\n privatekey: idp_private.pem # Specify the destination file for the generated private key.\r\n certificate: idp_cert.pem # Specify the destination file for the generated certificate.\r\n publickey: idp_public.pem # Specify the destination file for the generated public key.\r\n gen_jwt: # Specify whether to generate JWT for API key.\r\n enabled: true # Specify whether to enable JWT generation for API key.\r\n privatekey: idp_private.pem # Specify the private key file for JWT generation.\r\n privatekey_passphrase: # Specify the passphrase for the private key file.\r\n # If the private key is encrypted, specify the passphrase here.\r\n algorithm: RS256 # Specify the algorithm used to generate the JWT. The value can be RS256, PS256, or ES256.\r\n claims: # Specify the claims to be included in the JWT.\r\n iss: identity_provider # Specify the issuer of the JWT. This is usually the name of the identity provider.\r\n sub: app_user # Specify the subject of the JWT. This is usually the name of the application.\r\n aud: app_organization # Specify the audience of the JWT. This is usually the name of the organization that will use the application.\r\n exp: 31536000 # Specify the expiration time of the JWT in seconds. The default is 31536000 seconds (1 year).\r\n verify_jwt: # Specify whether to verify JWT for API key.\r\n enabled: true # Specify whether to enable JWT verification for API key.\r\n certificate: idp_cert.pem # Specify the certificate file for JWT verification.\r\n publickey: idp_public.pem # Specify the public key file for JWT verification. Not required if certificate exists.\r\n issuer: identity_provider # Specify the issuer of the JWT. This is usually the name of the identity provider. (If not specified, no verification)\r\n audience: app_organization # Specify the audience of the JWT. This is usually the name of the organization that will use the application. (If not specified, no verification)\r\n algorithm: RS256 # Specify the algorithm used to verify the JWT. The value can be RS256, PS256, or ES256.\r\noauth2: # OAuth2 settings.\r\n providers: # This is a per-provider setting for OAuth2.\r\n google: # Google's OAuth2 configuration.\r\n enabled: false # Specify whether to enable Google's OAuth2.\r\n client_id: XXXXXXXXXXX # Specify Google's OAuth2 client ID.\r\n client_secret: XXXXXXXXXXX # Specify Google's OAuth2 client secret.\r\n redirect_uri: https://localhost:8443/oauth2/google/callback # Specify Google's OAuth2 redirect URI.\r\n scope: ['email'] # Specify the scope you want to retrieve with Google's OAuth2. Usually, just reading the email is sufficient.\r\n signin_module: # Specify the module name that implements the sign-in.\r\n cmdbox.app.auth.google_signin\r\n note: # Specify a description such as Google's OAuth2 reference site.\r\n - https://developers.google.com/identity/protocols/oauth2/web-server?hl=ja#httprest\r\n github: # OAuth2 settings for GitHub.\r\n enabled: false # Specify whether to enable OAuth2 for GitHub.\r\n client_id: XXXXXXXXXXX # Specify the OAuth2 client ID for GitHub.\r\n client_secret: XXXXXXXXXXX # Specify the GitHub OAuth2 client secret.\r\n redirect_uri: https://localhost:8443/oauth2/github/callback # Specify the OAuth2 redirect URI for GitHub.\r\n scope: ['user:email'] # Specify the scope you want to get from GitHub's OAuth2. Usually, just reading the email is sufficient.\r\n signin_module: # Specify the module name that implements the sign-in.\r\n cmdbox.app.auth.github_signin\r\n note: # Specify a description, such as a reference site for OAuth2 on GitHub.\r\n - https://docs.github.com/ja/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#scopes\r\n azure: # OAuth2 settings for Azure AD.\r\n enabled: false # Specify whether to enable OAuth2 for Azure AD.\r\n tenant_id: XXXXXXXXXXX # Specify the tenant ID for Azure AD.\r\n client_id: XXXXXXXXXXX # Specify the OAuth2 client ID for Azure AD.\r\n client_secret: XXXXXXXXXXX # Specify the Azure AD OAuth2 client secret.\r\n redirect_uri: https://localhost:8443/oauth2/azure/callback # Specify the OAuth2 redirect URI for Azure AD.\r\n scope: ['openid', 'profile', 'email', 'https://graph.microsoft.com/mail.read']\r\n signin_module: # Specify the module name that implements the sign-in.\r\n cmdbox.app.auth.azure_signin\r\n note: # Specify a description, such as a reference site for Azure AD's OAuth2.\r\n - https://learn.microsoft.com/ja-jp/entra/identity-platform/v2-oauth2-auth-code-flow\r\nsaml: # SAML settings.\r\n providers: # This is a per-provider setting for OAuth2.\r\n azure: # SAML settings for Azure AD.\r\n enabled: false # Specify whether to enable SAML authentication for Azure AD.\r\n signin_module: # Specify the module name that implements the sign-in.\r\n cmdbox.app.auth.azure_signin_saml # Specify the python3-saml configuration.\r\n # see) https://github.com/SAML-Toolkits/python3-saml\r\n sp:\r\n entityId: https://localhost:8443/\r\n assertionConsumerService:\r\n url: https://localhost:8443/saml/azure/callback\r\n binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\r\n attributeConsumingService: {}\r\n singleLogoutService:\r\n binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\r\n NameIDFormat: urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\r\n x509cert: ''\r\n privateKey: ''\r\n idp:\r\n entityId: https://sts.windows.net/{tenant-id}/\r\n singleSignOnService:\r\n url: https://login.microsoftonline.com/{tenant-id}/saml2\r\n binding: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\r\n x509cert: XXXXXXXXXXX\r\n singleLogoutService: {}\r\n certFingerprint: ''\r\n certFingerprintAlgorithm: sha1\r\n\r\n```\r\n\r\n- See the documentation for references to each file.\r\n- Documentation is [here](https://hamacom2004jp.github.io/cmdbox/).\r\n\r\n\r\n# Lisence\r\n\r\nThis project is licensed under the MIT License, see the LICENSE file for details\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "cmdbox: It is a command line application with a plugin mechanism.",
"version": "0.6.2.3",
"project_urls": {
"Download": "https://github.com/hamacom2004jp/cmdbox",
"Homepage": "https://github.com/hamacom2004jp/cmdbox"
},
"split_keywords": [
"cli",
"restapi",
"redis",
"fastapi"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "55f3789d77ca7b86145238f50f99456aed31c9d53aa16fc5116924c4ae08f83c",
"md5": "57ca47eaf357c4ff1057d300ab6c4358",
"sha256": "1c54fe5d3aaef2cd915a0047f9fa59e38380532191e8d333409f21559b73d521"
},
"downloads": -1,
"filename": "cmdbox-0.6.2.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "57ca47eaf357c4ff1057d300ab6c4358",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 2264216,
"upload_time": "2025-07-13T04:25:53",
"upload_time_iso_8601": "2025-07-13T04:25:53.377645Z",
"url": "https://files.pythonhosted.org/packages/55/f3/789d77ca7b86145238f50f99456aed31c9d53aa16fc5116924c4ae08f83c/cmdbox-0.6.2.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "f751f52bea7c2d055062b511e34999ab9ff170211353f6f525348c0e4ad1400d",
"md5": "54c896135a55e95c239f92481c19553d",
"sha256": "cc0d20c1acf79283ef2bd22ad6b28d25c9a8a526ed3527f923162f34f690243c"
},
"downloads": -1,
"filename": "cmdbox-0.6.2.3.tar.gz",
"has_sig": false,
"md5_digest": "54c896135a55e95c239f92481c19553d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 1890521,
"upload_time": "2025-07-13T04:25:55",
"upload_time_iso_8601": "2025-07-13T04:25:55.108145Z",
"url": "https://files.pythonhosted.org/packages/f7/51/f52bea7c2d055062b511e34999ab9ff170211353f6f525348c0e4ad1400d/cmdbox-0.6.2.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-13 04:25:55",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "hamacom2004jp",
"github_project": "cmdbox",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "argcomplete",
"specs": []
},
{
"name": "async-timeout",
"specs": []
},
{
"name": "collectlicense",
"specs": []
},
{
"name": "cryptography",
"specs": []
},
{
"name": "fastapi",
"specs": []
},
{
"name": "gevent",
"specs": []
},
{
"name": "gunicorn",
"specs": []
},
{
"name": "itsdangerous",
"specs": []
},
{
"name": "numpy",
"specs": []
},
{
"name": "Pillow",
"specs": []
},
{
"name": "python-multipart",
"specs": []
},
{
"name": "pycryptodome",
"specs": []
},
{
"name": "plyer",
"specs": []
},
{
"name": "psycopg",
"specs": []
},
{
"name": "pyjwt",
"specs": []
},
{
"name": "pystray",
"specs": []
},
{
"name": "questionary",
"specs": []
},
{
"name": "redis",
"specs": []
},
{
"name": "requests",
"specs": []
},
{
"name": "rich",
"specs": []
},
{
"name": "six",
"specs": []
},
{
"name": "sphinx",
"specs": []
},
{
"name": "sphinx-rtd-theme",
"specs": []
},
{
"name": "sphinx_fontawesome",
"specs": []
},
{
"name": "sphinx-intl",
"specs": []
},
{
"name": "sphinx-sitemap",
"specs": []
},
{
"name": "tabulate",
"specs": []
},
{
"name": "twine",
"specs": []
},
{
"name": "uvicorn",
"specs": []
},
{
"name": "wheel",
"specs": []
}
],
"lcname": "cmdbox"
}