Gramex 1.94 release notes

Gramex 1.94 features @gramex charts, ChatGPTHandler upgrade, DriveHandler S3 support, and more.

@gramex charts

@gramex charts are configurable charts built on D3 under the @gramex/ namespace. These may be used as standalone libraries in any application.

This release includes:

ChatGPTHandler upgrade

In November, OpenAI modified the API with a breaking change to the streaming API.

Earlier, each each data chunk used to contain a complete JSON. Now, the JSON can be split across multiple chunks. ChatGPTHandler now factors this in.

#777

DriveHandler S3 support

DriveHandler supports S3 as a back-end.

To store files in S3, use the storage: configuration. For example:

url:
  s3drive:
    pattern: /$YAMLURL/s3drive
    handler: DriveHandler
    kwargs:
      path: $YAMLPATH/files/
      storage:
        type: s3
        bucket: path/to/my-bucket

Set up the AWS Credentials in environment variables

export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...  # Optional

This stores all files in your S3 path/to/my-bucket bucket. Metadata is still stored under the path as .meta.db.

#768

Header validation

All handlers support a validate: key to validate requests based on headers. For example:

url:
  auth/validate:
    pattern: /$YAMLURL/validate
    handler: FileHandler
    kwargs:
      path: $YAMLPATH/secret.html
      validate: handler.request.headers['Host'] == 'example.org'

This allows access only if the Host header is example.org.

You can use any Python expression. If the expression returns a falsy value or raises an Exception, Gramex raises a HTTP 400 error.

Specify multiple conditions with a list. Gramex allows the request only if ALL conditions match. For example:

validate:
  - handler.request.headers['Host'] == 'example.org'
  - handler.request.headers['User-Agent'].startswith('Mozilla')
  - handler.current_user['id'] == 'alpha'

Customize the HTTP code and reason by specifing a dictionary with function, code, and reason. For example:

validate:
  - function: handler.request.headers['Host'] == 'example.org'
    code: 403
    reason: This app should only be hosted on example.org
  - function: handler.request.headers['User-Agent'].startswith('Mozilla')
    code: 400
    reason: Only Chrome, Edge, Firefox, and Safari are supported

#766

OTP reset

DBAuth, EmailAuth, and SMSAuth now support resetting OTPs.

Add the otp_reset: true key to the kwargs: section (or forgot: sub-section for DBAuth). This invalidates any previous OTPs sent to the user.

#766

Improved Gramex setup

gramex setup ran setup.sh only if bash was available. Now it runs setup.sh if bash, sh or ash is available.

#775

CaptureHandler supports patterns

CaptureHandler supports a pattern: kwarg that restricts the URLs CaptureHandler can access.

For example:, pattern: ^http only allows URLs that start with http, disallowing file:// and other such URLs. (Relative URLs like ../ are converted to absolute HTTP URLs before checking the pattern, so they will work fine.)

To only allow specific domains, e.g. gramener.com and gramener.co, use:

pattern: ^https?://(www\.)?(gramener\.com|gramener\.co)/

#762

Bug fixes

Backward compatibility & security

Gramex 1.94 is backward compatible with previous releases unless the release notes say otherwise. We ensure this with automated tests.

Every Gramex release is tested for security vulnerabilities using the following tools.

  1. Bandit tests for back-end Python vulnerabilities. See Bandit results
  2. npm-audit tests for front-end JavaScript vulnerabilities. See npm-audit results
  3. Snyk for front-end and back-end vulnerabilities. See Synk results
  4. ClamAV for anti-virus scans. See ClamAV results
  5. Trivy for container scans. See Trivy results

Statistics

The Gramex code base has:

How to install

See the Gramex installation and upgrade instructions.